[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] gr-error-correcting-codes/src/lib Makefile.am e...
From: |
Michael Dickens |
Subject: |
[Commit-gnuradio] gr-error-correcting-codes/src/lib Makefile.am e... |
Date: |
Wed, 05 Jul 2006 17:49:59 +0000 |
CVSROOT: /sources/gnuradio
Module name: gr-error-correcting-codes
Changes by: Michael Dickens <michaelld> 06/07/05 17:49:58
Modified files:
src/lib : Makefile.am ecc.i gr_syms_to_metrics.cc
src/lib/libecc : Makefile.am code_metrics.cc decoder.h
encoder_convolutional_ic1_ic1.h
Added files:
src/lib : gr_decoder_viterbi_block_full.cc
gr_decoder_viterbi_block_full.h
gr_decoder_viterbi_block_full.i
src/lib/libecc : decoder.cc decoder_viterbi.cc decoder_viterbi.h
decoder_viterbi_block_full.cc
decoder_viterbi_block_full.h
decoder_viterbi_block_full_ic1.h
Removed files:
src/lib : gr_decoder_viterbi_block_soft_full.cc
gr_decoder_viterbi_block_soft_full.h
gr_decoder_viterbi_block_soft_full.i
src/lib/libecc : decoder_viterbi_base.h
encoder_convolutional_base.cc
encoder_convolutional_base.h
Log message:
Work in progress. Creating decoder classes & updating .am and .i
files for these additions.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/Makefile.am?cvsroot=gnuradio&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/ecc.i?cvsroot=gnuradio&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.cc?cvsroot=gnuradio&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_full.cc?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_full.h?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_full.i?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_soft_full.cc?cvsroot=gnuradio&r1=1.1&r2=0
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_soft_full.h?cvsroot=gnuradio&r1=1.1&r2=0
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_soft_full.i?cvsroot=gnuradio&r1=1.1&r2=0
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/Makefile.am?cvsroot=gnuradio&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/code_metrics.cc?cvsroot=gnuradio&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/decoder.h?cvsroot=gnuradio&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic1_ic1.h?cvsroot=gnuradio&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/decoder.cc?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.cc?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.h?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_block_full.cc?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_block_full.h?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_block_full_ic1.h?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_base.h?cvsroot=gnuradio&r1=1.2&r2=0
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_base.cc?cvsroot=gnuradio&r1=1.2&r2=0
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_base.h?cvsroot=gnuradio&r1=1.2&r2=0
Patches:
Index: Makefile.am
===================================================================
RCS file: /sources/gnuradio/gr-error-correcting-codes/src/lib/Makefile.am,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- Makefile.am 3 Jul 2006 02:12:53 -0000 1.1
+++ Makefile.am 5 Jul 2006 17:49:58 -0000 1.2
@@ -44,7 +44,7 @@
LOCAL_IFILES = \
gr_syms_to_metrics.i \
- gr_decoder_viterbi_block_soft_full.i \
+ gr_decoder_viterbi_block_full.i \
gr_streams_encode_convolutional.i \
ecc.i
@@ -66,7 +66,7 @@
# These are the source files that go into the shared library
_ecc_la_SOURCES = \
gr_syms_to_metrics.cc \
- gr_decoder_viterbi_block_soft_full.cc \
+ gr_decoder_viterbi_block_full.cc \
gr_streams_encode_convolutional.cc \
ecc.cc
@@ -85,7 +85,7 @@
# These headers get installed in ${prefix}/include/gnuradio
grinclude_HEADERS = \
gr_syms_to_metrics.h \
- gr_decoder_viterbi_block_soft_full.h \
+ gr_decoder_viterbi_block_full.h \
gr_streams_encode_convolutional.h
# These swig headers get installed in ${prefix}/include/gnuradio/swig
Index: ecc.i
===================================================================
RCS file: /sources/gnuradio/gr-error-correcting-codes/src/lib/ecc.i,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- ecc.i 3 Jul 2006 02:12:53 -0000 1.1
+++ ecc.i 5 Jul 2006 17:49:58 -0000 1.2
@@ -28,12 +28,12 @@
#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix
#include <gr_streams_encode_convolutional.h>
-#include <gr_decoder_viterbi_block_soft_full.h>
+#include <gr_decoder_viterbi_block_full.h>
#include <gr_syms_to_metrics.h>
#include <stdexcept>
%}
%include "gr_streams_encode_convolutional.i"
-%include "gr_decoder_viterbi_block_soft_full.i"
+%include "gr_decoder_viterbi_block_full.i"
%include "gr_syms_to_metrics.i"
Index: gr_syms_to_metrics.cc
===================================================================
RCS file:
/sources/gnuradio/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.cc,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- gr_syms_to_metrics.cc 3 Jul 2006 02:12:53 -0000 1.1
+++ gr_syms_to_metrics.cc 5 Jul 2006 17:49:58 -0000 1.2
@@ -45,8 +45,10 @@
sample_precision));
}
-// dummy functions to get the float(*)(float) function to work
-// properly with the gr_feval_XX stuff.
+/*
+ * dummy functions and variables to get the float(*)(float) function
+ * to work properly with the gr_feval_XX stuff.
+ */
static gr_feval_ff* l_pdf_fcn_0_bit;
static gr_feval_ff* l_pdf_fcn_1_bit;
@@ -82,16 +84,16 @@
l_pdf_fcn_1_bit = pdf_fcn_1_bit;
if (sample_precision == 0) {
-// float
- d_out_item_size_bytes = 4;
+ // float
+ d_out_item_size_bytes = sizeof (float);
d_code_metrics = new code_metric_ff (&pdf_fcn_0,
&pdf_fcn_1,
n_samples,
min_sample,
max_sample);
} else if (sample_precision <= 8) {
-// use char
- d_out_item_size_bytes = 1;
+ // use char
+ d_out_item_size_bytes = sizeof (char);
d_code_metrics = new code_metric_fb (&pdf_fcn_0,
&pdf_fcn_1,
n_samples,
@@ -99,8 +101,8 @@
max_sample,
sample_precision);
} else if (sample_precision <= 16) {
-// use short
- d_out_item_size_bytes = 2;
+ // use short
+ d_out_item_size_bytes = sizeof (short);
d_code_metrics = new code_metric_fs (&pdf_fcn_0,
&pdf_fcn_1,
n_samples,
@@ -108,8 +110,8 @@
max_sample,
sample_precision);
} else {
-// use long
- d_out_item_size_bytes = 4;
+ // use long
+ d_out_item_size_bytes = sizeof (long);
d_code_metrics = new code_metric_fl (&pdf_fcn_0,
&pdf_fcn_1,
n_samples,
@@ -131,14 +133,15 @@
(int noutput_items,
gr_vector_int &ninput_items_required)
{
-// always 1:1, for all streams
+ // always 1:1, for all streams
for (size_t n = 0; n < ninput_items_required.size(); n++) {
ninput_items_required[n] = noutput_items;
}
}
int
-gr_syms_to_metrics::general_work (int noutput_items,
+gr_syms_to_metrics::general_work
+(int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
@@ -154,9 +157,11 @@
t_out_buf_0_bit, t_out_buf_1_bit);
}
-// consume the number of used input items on all input streams
+ // consume the number of used input items on all input streams
+
consume_each (noutput_items);
-// returns number of items written to each output stream
+ // returns number of items written to each output stream
+
return (noutput_items);
}
Index: libecc/Makefile.am
===================================================================
RCS file:
/sources/gnuradio/gr-error-correcting-codes/src/lib/libecc/Makefile.am,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- libecc/Makefile.am 4 Jul 2006 20:57:32 -0000 1.3
+++ libecc/Makefile.am 5 Jul 2006 17:49:58 -0000 1.4
@@ -29,14 +29,18 @@
libecc_la_SOURCES = \
encoder.cc code_metrics.cc \
- encoder_convolutional_base.cc \
- encoder_convolutional_ic1_ic1.cc
+ encoder_convolutional.cc \
+ encoder_convolutional_ic1_ic1.cc \
+ decoder.cc decoder_viterbi.cc \
+ decoder_viterbi_block_full.cc
noinst_HEADERS = \
encoder.h code_metrics.h \
- encoder_convolutional_base.h \
+ encoder_convolutional.h \
encoder_convolutional_ic1_ic1.h \
- decoder.h decoder_viterbi_base.h
+ decoder.h decoder_viterbi.h \
+ decoder_viterbi_block_full.h \
+ decoder_viterbi_block_full_ic1.h
# link the library against the c++ standard library
libecc_la_LIBADD = \
Index: libecc/code_metrics.cc
===================================================================
RCS file:
/sources/gnuradio/gr-error-correcting-codes/src/lib/libecc/code_metrics.cc,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libecc/code_metrics.cc 4 Jul 2006 20:57:32 -0000 1.2
+++ libecc/code_metrics.cc 5 Jul 2006 17:49:58 -0000 1.3
@@ -28,7 +28,8 @@
#include <iostream>
#include <math.h>
-code_metric_ff::code_metric_ff (pdf_fcn_t pdf_fcn_0_bit,
+code_metric_ff::code_metric_ff
+(pdf_fcn_t pdf_fcn_0_bit,
pdf_fcn_t pdf_fcn_1_bit,
size_t n_samples,
pdf_fcn_io_t min_sample,
@@ -109,7 +110,8 @@
lookup (*sym++, (void*) l_bit_0++, (void*) l_bit_1++);
}
-code_metric_fl::code_metric_fl (pdf_fcn_t pdf_fcn_0_bit,
+code_metric_fl::code_metric_fl
+(pdf_fcn_t pdf_fcn_0_bit,
pdf_fcn_t pdf_fcn_1_bit,
size_t n_samples,
pdf_fcn_io_t min_sample,
@@ -152,10 +154,10 @@
d_metric_table_0_bit.assign (n_samples, 0);
d_metric_table_1_bit.assign (n_samples, 0);
-// get the scale factor for converting from float to sample_precision
-// maps:
-// logf (pdf_fcn_0_bit->eval (d_min_sample)) -> l_min_map
-// logf (pdf_fcn_0_bit->eval (d_max_sample)) -> l_max_map
+ // get the scale factor for converting from float to sample_precision
+ // maps:
+ // logf (pdf_fcn_0_bit->eval (d_min_sample)) -> l_min_map
+ // logf (pdf_fcn_0_bit->eval (d_max_sample)) -> l_max_map
metric_t l_min_map = - (1 << (sample_precision - 1));
@@ -219,7 +221,8 @@
lookup (*sym++, (void*) l_bit_0++, (void*) l_bit_1++);
}
-code_metric_fs::code_metric_fs (pdf_fcn_t pdf_fcn_0_bit,
+code_metric_fs::code_metric_fs
+(pdf_fcn_t pdf_fcn_0_bit,
pdf_fcn_t pdf_fcn_1_bit,
size_t n_samples,
pdf_fcn_io_t min_sample,
@@ -262,10 +265,10 @@
d_metric_table_0_bit.assign (n_samples, 0);
d_metric_table_1_bit.assign (n_samples, 0);
-// get the scale factor for converting from float to sample_precision
-// maps:
-// logf (pdf_fcn_0_bit->eval (d_min_sample)) -> l_min_map
-// logf (pdf_fcn_0_bit->eval (d_max_sample)) -> l_max_map
+ // get the scale factor for converting from float to sample_precision
+ // maps:
+ // logf (pdf_fcn_0_bit->eval (d_min_sample)) -> l_min_map
+ // logf (pdf_fcn_0_bit->eval (d_max_sample)) -> l_max_map
metric_t l_min_map = - (1 << (sample_precision - 1));
@@ -329,7 +332,8 @@
lookup (*sym++, (void*) l_bit_0++, (void*) l_bit_1++);
}
-code_metric_fb::code_metric_fb (pdf_fcn_t pdf_fcn_0_bit,
+code_metric_fb::code_metric_fb
+(pdf_fcn_t pdf_fcn_0_bit,
pdf_fcn_t pdf_fcn_1_bit,
size_t n_samples,
pdf_fcn_io_t min_sample,
@@ -372,10 +376,10 @@
d_metric_table_0_bit.assign (n_samples, 0);
d_metric_table_1_bit.assign (n_samples, 0);
-// get the scale factor for converting from float to sample_precision
-// maps:
-// logf (pdf_fcn_0_bit->eval (d_min_sample)) -> l_min_map
-// logf (pdf_fcn_0_bit->eval (d_max_sample)) -> l_max_map
+ // get the scale factor for converting from float to sample_precision
+ // maps:
+ // logf (pdf_fcn_0_bit->eval (d_min_sample)) -> l_min_map
+ // logf (pdf_fcn_0_bit->eval (d_max_sample)) -> l_max_map
metric_t l_min_map = - (1 << (sample_precision - 1));
Index: libecc/decoder.h
===================================================================
RCS file: /sources/gnuradio/gr-error-correcting-codes/src/lib/libecc/decoder.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- libecc/decoder.h 4 Jul 2006 20:57:32 -0000 1.2
+++ libecc/decoder.h 5 Jul 2006 17:49:58 -0000 1.3
@@ -47,11 +47,17 @@
size_t n_bits_to_input,
char** out_buf) = 0;
+protected:
+ virtual void decode_private (const char** in_buf, char** out_buf) = 0;
+ virtual char get_next_input (const char** in_buf, size_t code_input_n) = 0;
+ virtual void output_bit (char t_out_bit, char** out_buf,
+ size_t t_output_stream) = 0;
+
size_t d_frame_size_bits, d_n_code_inputs, d_n_code_outputs;
- size_t d_max_memory, d_n_enc_bits;
+ size_t d_max_memory, d_n_enc_bits, d_sample_precision;
memory_t d_max_mem_mask;
memory_t d_in_buf_ndx, d_out_buf_ndx;
- memory_t d_in_bit_shift, d_out_bit_shift;
+ memory_t d_out_bit_shift;
size_t d_n_input_bits_left, d_n_output_bits_left;
};
Index: libecc/encoder_convolutional_ic1_ic1.h
===================================================================
RCS file:
/sources/gnuradio/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic1_ic1.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- libecc/encoder_convolutional_ic1_ic1.h 4 Jul 2006 20:57:32 -0000
1.1
+++ libecc/encoder_convolutional_ic1_ic1.h 5 Jul 2006 17:49:58 -0000
1.2
@@ -23,11 +23,13 @@
#ifndef INCLUDED_ENCODER_CONVOLUTIONAL_IC1_IC1_H
#define INCLUDED_ENCODER_CONVOLUTIONAL_IC1_IC1_H
-#include <vector>
-#include "encoder_convolutional_base.h"
+#include "encoder_convolutional.h"
+class encoder_convolutional_ic1_ic1 : public encoder_convolutional
+{
+public:
/*!
- * class encoder_convolutional_ic1_ic1 : public encoder_convolutional_base
+ * class encoder_convolutional_ic1_ic1 : public encoder_convolutional
*
* Encode the incoming streams using a convolutional encoder,
* "feedforward" or feedback. Optional termination, data
@@ -42,9 +44,6 @@
* the single output bit per output item.
*/
-class encoder_convolutional_ic1_ic1 : public encoder_convolutional_base
-{
-public:
inline encoder_convolutional_ic1_ic1 (int frame_size_bits,
int n_code_inputs,
int n_code_outputs,
@@ -52,7 +51,7 @@
bool do_termination = true,
int start_memory_state = 0,
int end_memory_state = 0)
- : encoder_convolutional_base (frame_size_bits,
+ : encoder_convolutional (frame_size_bits,
n_code_inputs,
n_code_outputs,
code_generators,
@@ -68,7 +67,7 @@
bool do_termination = true,
int start_memory_state = 0,
int end_memory_state = 0)
- : encoder_convolutional_base (frame_size_bits,
+ : encoder_convolutional (frame_size_bits,
n_code_inputs,
n_code_outputs,
code_generators,
Index: gr_decoder_viterbi_block_full.cc
===================================================================
RCS file: gr_decoder_viterbi_block_full.cc
diff -N gr_decoder_viterbi_block_full.cc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_decoder_viterbi_block_full.cc 5 Jul 2006 17:49:58 -0000 1.1
@@ -0,0 +1,208 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio.
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_decoder_viterbi_block_full.h>
+#include <gr_io_signature.h>
+#include <assert.h>
+#include <iostream>
+
+gr_decoder_viterbi_block_full_sptr
+gr_make_decoder_viterbi_block_full
+(int sample_precision,
+ int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> code_generator,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state)
+{
+ return gr_decoder_viterbi_block_full_sptr
+ (new gr_decoder_viterbi_block_full (sample_precision,
+ frame_size_bits,
+ n_code_inputs,
+ n_code_outputs,
+ code_generator,
+ do_termination,
+ start_memory_state,
+ end_memory_state));
+}
+
+gr_decoder_viterbi_block_full_sptr
+gr_make_decoder_viterbi_block_full
+(int sample_precision,
+ int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> code_generator,
+ std::vector<int> code_feedback,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state)
+{
+ return gr_decoder_viterbi_block_full_sptr
+ (new gr_decoder_viterbi_block_full (sample_precision,
+ frame_size_bits,
+ n_code_inputs,
+ n_code_outputs,
+ code_generator,
+ code_feedback,
+ do_termination,
+ start_memory_state,
+ end_memory_state));
+}
+
+gr_decoder_viterbi_block_full::gr_decoder_viterbi_block_full
+(int sample_precision,
+ int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state)
+ : gr_block ("decoder_viterbi_block_full",
+ gr_make_io_signature (0, 0, 0),
+ gr_make_io_signature (0, 0, 0))
+{
+ d_encoder = new encoder_convolutional_ic1_ic1 (frame_size_bits,
+ n_code_inputs,
+ n_code_outputs,
+ code_generator,
+ do_termination,
+ start_memory_state,
+ end_memory_state);
+
+ d_n_code_inputs = n_code_inputs;
+ d_n_code_outputs = n_code_outputs;
+
+ d_decoder = new decoder_viterbi_block_ic1_ic1 (sample_precision,
+ d_encoder);
+
+ setup_io_signatures (sample_precision);
+}
+
+gr_decoder_viterbi_block_full::gr_decoder_viterbi_block_full
+(int sample_precision,
+ int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ std::vector<int> code_feedback,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state)
+ : gr_block ("decoder_viterbi_block_full",
+ gr_make_io_signature (0, 0, 0),
+ gr_make_io_signature (0, 0, 0))
+{
+ d_encoder = new encoder_convolutional_ic1_ic1 (frame_size_bits,
+ n_code_inputs,
+ n_code_outputs,
+ code_generator,
+ code_feedback,
+ do_termination,
+ start_memory_state,
+ end_memory_state);
+
+ d_n_code_inputs = n_code_inputs;
+ d_n_code_outputs = n_code_outputs;
+
+ d_decoder = new decoder_viterbi_block_full_ic1_ic1 (sample_precision,
+ d_encoder);
+
+ setup_io_signatures (sample_precision);
+}
+
+gr_decoder_viterbi_block_full::~gr_decoder_viterbi_block_full
+()
+{
+ delete d_decoder;
+ delete d_encoder;
+}
+
+void
+gr_decoder_viterbi_block_full::setup_io_signatures
+(int sample_precision)
+{
+ if ((sample_precision < 0) | (sample_precision > 32)) {
+ std::cerr << "gr_decoder_viterbi_block_full: "
+ "The provided sample_precision (" << sample_precision <<
+ ") must be between 0 and 32.\n";
+ assert (0);
+ }
+
+ // output signature is always the same:
+ // sizeof (char) with 1 bit per char as the LSB
+
+ set_output_signature (gr_make_io_signature (d_n_code_inputs,
+ d_n_code_inputs,
+ sizeof (char)));
+
+ // determine the input signature element size
+ size_t l_input_item_size_bytes
+ if (sample_precision == 0) {
+ // float
+ l_input_item_size_bytes = sizeof (float);
+ } else if (sample_precision <= 8) {
+ // use char
+ l_input_item_size_bytes = sizeof (char);
+ } else if (sample_precision <= 16) {
+ // use short
+ l_input_item_size_bytes = sizeof (short);
+ } else {
+ // use long
+ l_input_item_size_bytes = sizeof (long);
+ }
+
+ set_input_signature (gr_make_io_signature (2*d_n_code_outputs,
+ 2*d_n_code_outputs,
+ l_input_item_size_bytes));
+}
+
+void gr_decoder_viterbi_block_full::forecast
+(int noutput_items,
+ gr_vector_int &ninput_items_required)
+{
+ int ninput_items = d_decoder->compute_n_input_bits (noutput_items);
+ size_t ninputs = ninput_items_required.size();
+ for (size_t n = 0; n < ninputs; n++)
+ ninput_items_required[n] = ninput_items;
+}
+
+int
+gr_decoder_viterbi_block_full::general_work
+(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ size_t
+
+
+// returns number of items written to each output stream
+ return (t_noutput_items);
+}
Index: gr_decoder_viterbi_block_full.h
===================================================================
RCS file: gr_decoder_viterbi_block_full.h
diff -N gr_decoder_viterbi_block_full.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_decoder_viterbi_block_full.h 5 Jul 2006 17:49:58 -0000 1.1
@@ -0,0 +1,120 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_GR_DECODER_VITERBI_BLOCK_FULL_H
+#define INCLUDED_GR_DECODER_VITERBI_BLOCK_FULL_H
+
+#include <gr_block.h>
+#include <vector>
+#include <sys/types.h>
+#include <libecc/decoder_viterbi_block_full_ic1.h>
+
+class gr_decoder_viterbi_block_full;
+typedef boost::shared_ptr<gr_decoder_viterbi_block_full>
+gr_decoder_viterbi_block_full_sptr;
+
+gr_decoder_viterbi_block_full_sptr gr_make_decoder_viterbi_block_full
+(int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> code_generator,
+ bool do_termination = true,
+ int start_memory_state = 0,
+ int end_memory_state = 0);
+
+/*!
+ * \brief Decode the incoming streams using a Viterbi-style decoder
+ *
+ * input: encoded data as soft symbols, either as individual
+ * streams or mux'ed into 1 stream.
+ *
+ * output: stream(s) of user-defined element size.
+ */
+
+class gr_decoder_viterbi_block_full : public gr_block
+{
+ friend gr_decoder_viterbi_block_full_sptr
+ gr_make_decoder_viterbi_block_full (int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> code_generator,
+ bool do_termination = true,
+ int start_memory_state = 0,
+ int end_memory_state = 0);
+/*
+ * frame_size_bits: if == 0, then do streaming decoding (infinite
+ * trellis); otherwise this is the block size to decode before
+ * terminating the trellis.
+ *
+ * code_generator: vector of integers (32 bit) representing the code
+ * to be implemented in octal form. E.g. "04" in binary is "100",
+ * which would be "D^2" for code generation. "06" == 110b == "D^2 + D"
+ * ==> The vector is listed in order for each input stream, so if there
+ * are 2 input streams (I1, I2) [specified in "n_code_inputs"]
+ * and 2 output streams (O1, O2) [specified in "n_code_outputs"],
+ * then the vector would be the code generator for:
+ * [I1->O1, I1->O2, I2->O1, I2->O2]
+ * with each element being the octal representation of the code.
+ *
+ * do_termination is valid only if frame_size_bits != 0, and defines
+ * whether or not to to trellis termination.
+ *
+ * do_mux_input: is true, then the one input stream will be
+ * interpreted as the multiplexing all of the input bits. For
+ * example for a 3 input decoder, the input stream would be
+ * [I1[k], I2[k], I3[k], I1[k+1], I2[k+1], ...], where "k" is the
+ * input sample time, and "I1" through "I3" are the 3 input
+ * streams.
+ *
+ * n_code_inputs: the number of decoder-input (encoder-output)
+ * streams, no matter if separate or mux'ed
+ *
+ * n_code_outputs: the number of decoder-output (encoder-input) streams
+ */
+
+ gr_decoder_viterbi_block_full (int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> code_generator,
+ bool do_termination = true,
+ int start_memory_state = 0,
+ int end_memory_state = 0);
+
+public:
+ ~gr_decoder_viterbi_block_full ();
+
+ virtual void forecast (int noutput_items,
+ gr_vector_int &ninput_items_required);
+
+ virtual int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+protected:
+ int d_n_code_inputs, d_n_code_outputs;
+
+ decoder* d_decoder;
+ encoder* d_encoder;
+};
+
+#endif /* INCLUDED_GR_DECODER_VITERBI_BLOCK_FULL_H */
Index: gr_decoder_viterbi_block_full.i
===================================================================
RCS file: gr_decoder_viterbi_block_full.i
diff -N gr_decoder_viterbi_block_full.i
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_decoder_viterbi_block_full.i 5 Jul 2006 17:49:58 -0000 1.1
@@ -0,0 +1,43 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,decoder_viterbi_block_soft_full);
+
+gr_decoder_viterbi_block_soft_full_sptr
+gr_make_decoder_viterbi_block_soft_full (int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> code_generator,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state);
+
+class gr_decoder_viterbi_block_soft_full : public gr_block
+{
+ gr_decoder_viterbi_block_soft_full (int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> code_generator,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state);
+};
Index: libecc/decoder.cc
===================================================================
RCS file: libecc/decoder.cc
diff -N libecc/decoder.cc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libecc/decoder.cc 5 Jul 2006 17:49:58 -0000 1.1
@@ -0,0 +1,104 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <decoder.h>
+#include <assert.h>
+#include <iostream>
+
+#define DO_PRINT_DEBUG 1
+
+#if DO_PRINT_DEBUG
+#include <mld/n2bs.h>
+#endif
+
+size_t
+decoder::decode
+(const char** in_buf,
+ char** out_buf,
+ size_t n_bits_to_output)
+{
+// set the class-internal number of input and
+// output bits left to decode
+ size_t saved_n_input_bits;
+ saved_n_input_bits = d_n_input_bits_left =
+ compute_n_input_bits (n_bits_to_output);
+ d_n_output_bits_left = n_bits_to_output;
+
+// call the private decode function
+ decode_private (in_buf, out_buf);
+
+#ifdef DO_PRINT_DEBUG
+ std::cout << "n_input_bits_used = " <<
+ (saved_n_input_bits - d_n_input_bits_left) << '\n';
+ std::cout << "n_output_bits_used = " <<
+ (n_bits_to_output - d_n_output_bits_left) << '\n';
+
+ assert (d_out_buf_ndx == n_bits_to_output);
+#endif
+
+// return the actual number of input bits used
+ return (saved_n_input_bits - d_n_input_bits_left);
+}
+
+/*
+ * decode a certain number of input bits
+ *
+ * the 'in_buf' and 'out_buf' must have enough memory to handle the
+ * number of input and output bits; no error checking is done!
+ *
+ * n_bits_to_input: is the number of input bits per input stream to decode
+ *
+ * returns the number of actual bits written to the output stream(s)
+ */
+
+size_t
+decoder::decode
+(const char** in_buf,
+ size_t n_bits_to_input,
+ char** out_buf)
+{
+// set the class-internal number of input and
+// output bits left to decode
+ size_t saved_n_output_bits;
+ saved_n_output_bits = d_n_output_bits_left =
+ compute_n_output_bits (n_bits_to_input);
+ d_n_input_bits_left = n_bits_to_input;
+
+// call the private decode function
+ decode_private (in_buf, out_buf);
+
+#ifdef DO_PRINT_DEBUG
+ std::cout << "n_input_bits_used = " <<
+ (n_bits_to_input - d_n_input_bits_left) << '\n';
+ std::cout << "n_output_bits_used = " <<
+ (saved_n_output_bits - d_n_output_bits_left) << '\n';
+
+ assert (d_in_buf_ndx == n_bits_to_input);
+#endif
+
+// return the actual number of input bits used
+ return (saved_n_output_bits - d_n_output_bits_left);
+}
Index: libecc/decoder_viterbi.cc
===================================================================
RCS file: libecc/decoder_viterbi.cc
diff -N libecc/decoder_viterbi.cc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libecc/decoder_viterbi.cc 5 Jul 2006 17:49:58 -0000 1.1
@@ -0,0 +1,1481 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <decoder_viterbi.h>
+#include <assert.h>
+#include <iostream>
+
+const int g_max_frame_size_bits = 10000000;
+const int g_max_num_streams = 10;
+const int g_num_bits_per_byte = 8;
+
+#define DO_TIME_THOUGHPUT 0
+#define DO_PRINT_DEBUG_INST 0
+#define DO_PRINT_DEBUG_INST_0 0
+#define DO_PRINT_DEBUG_INST_1 0
+#define DO_PRINT_DEBUG_INST_2 0
+#define DO_PRINT_DEBUG_FSM 0
+#define DO_PRINT_DEBUG_INIT 0
+#define DO_PRINT_DEBUG_UP 0
+#define DO_PRINT_DEBUG_UP_0 0
+#define DO_PRINT_DEBUG_UP_1 0
+#define DO_PRINT_DEBUG_MIDDLE 0
+#define DO_PRINT_DEBUG_MIDDLE_0 0
+#define DO_PRINT_DEBUG_MIDDLE_1 0
+#define DO_PRINT_DEBUG_TERM 0
+#define DO_PRINT_DEBUG_TERM_1 0
+#define DO_PRINT_DEBUG_OUTPUT 0
+#define DO_PRINT_DEBUG_OUTPUT_0 0
+#define DO_PRINT_DEBUG_EXIT 0
+#define DO_PRINT_DEBUG 0
+
+#if DO_TIME_THOUGHPUT
+#include <mld/mld_timer.h>
+#endif
+#if DO_PRINT_DEBUG
+#include <mld/n2bs.h>
+#endif
+
+decoder_viterbi::decoder_viterbi
+(int sample_precision,
+ int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> &code_generators,
+ bool do_termination = true,
+ int start_memory_state = 0,
+ int end_memory_state = 0)
+{
+ // make sure the sample precitions makes sense
+
+ if ((sample_precision < 0) | (sample_precision > 32)) {
+ std::cerr << "decoder_viterbi: "
+ "Requested sample_precision (" << sample_precision <<
+ "must be between 0 and 32.\n";
+ assert (0);
+ }
+
+ // the rest is handled by the encoder, but which encoder to use?
+
+
+
+ // make sure the frame length makes sense, #1 - more later
+
+ if (frame_size_bits > g_max_frame_size_bits) {
+ std::cerr << "decoder_viterbi: " <<
+ "Requested frame length (" << frame_size_bits <<
+ " bits) must be at most " << g_max_frame_size_bits << " bits.\n";
+ assert (0);
+ }
+
+// check to make sure the number of input streams makes sense
+ if ((n_code_inputs <= 0) | (n_code_inputs > g_max_num_streams)) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Requested number of input streams (" <<
+ n_code_inputs << ") must be between 1 and " <<
+ g_max_num_streams << ".\n";
+ assert (0);
+ }
+
+// check to make sure the number of output streams makes sense
+ if ((n_code_outputs <= 0) | (n_code_outputs > g_max_num_streams)) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Requested number of output streams (" <<
+ n_code_outputs << ") must be between 1 and " <<
+ g_max_num_streams << ".\n";
+ assert (0);
+ }
+
+// make sure the code_generator is the correct length
+ if (code_generators.size () !=
+ ((size_t)(n_code_inputs * n_code_outputs))) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Number of code generator entries (" << code_generators.size () <<
+ ") is not equal to the product of the number of input and output" <<
+ " streams (" << (n_code_inputs * n_code_outputs) << ").\n";
+ assert (0);
+ }
+
+// create the class frame variables
+ d_frame_size_bits = frame_size_bits;
+ d_out_stream_el_size_bytes = out_stream_el_size_bytes;
+ d_n_code_inputs = n_code_inputs;
+ d_n_code_outputs = n_code_outputs;
+ d_do_streaming = (frame_size_bits == 0);
+ d_do_termination = (d_do_streaming == true) ? false : do_termination;
+ d_do_mux_inputs = do_mux_inputs;
+
+// allocate the vectors for doing the encoding. use 32-bit int's
+// actual bits to represent memory and the code, as it makes the
+// operations quite simple the state vectors.
+// code generates are for each I/O combination
+
+ d_code_generators.resize (d_n_code_inputs * d_n_code_outputs, 0);
+
+// check the input code_generator for correctness & find the memory order
+// t_max_mem will be the mamimum number of memories used by the generator
+// t_code_ndx is a counter over all input code_generator elements
+ int t_max_mem = 0, t_code_ndx = d_code_generators.size() - 1;
+// loop over all input streams first, output streams second
+ for (int n = d_n_code_outputs - 1; n >= 0; n--) {
+ int t_all_inputs_zero = 0;
+ for (int m = d_n_code_inputs - 1; m >= 0; m--) {
+ int t_in_code = code_generators[t_code_ndx];
+ t_all_inputs_zero |= t_in_code;
+ int t_code_mem = 0;
+// find the memory requirement for this code generator
+ while (t_in_code != 0) {
+ t_in_code >>= 1;
+ t_code_mem++;
+ }
+ if (t_code_mem > t_max_mem)
+ t_max_mem = t_code_mem;
+// store in d_code_generators in output-first ordering
+ d_code_generators[(m*d_n_code_outputs) + n] =
+ code_generators[t_code_ndx--];
+ }
+ if (t_all_inputs_zero == 0) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "At least 1 generator code for encode-output " << n+1 <<
+ " must be non-0.\n";
+ assert (0);
+ }
+ }
+
+// store the maximum memory order (e.g. "2" -> D^2)
+ d_max_memory = t_max_mem - 1;
+
+// make sure the frame length makes sense, #2
+ if (d_frame_size_bits < d_max_memory) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Requested frame length (" << d_frame_size_bits <<
+ " bit" << (d_frame_size_bits > 1 ? "s" : "") <<
+ ") must be at least 1 memory length (" << d_max_memory <<
+ " bit" << (d_max_memory > 1 ? "s" : "") <<
+ " for this code).\n";
+ assert (0);
+ }
+
+// NOTE: d_n_states is a 'u_long', and thus is quite limited in terms
+// of max memory and # of input streams to 2^32 states
+// This is OK, since that many states would be impossibly slow to decode!
+// might make this a "long long" (64 bits) in the future
+ d_n_states = 1 << (d_max_memory * d_n_code_inputs);
+ d_n_input_combinations = 1 << d_n_code_inputs;
+
+#if DO_PRINT_DEBUG_INST_0
+ std::cout << "Init:\n" <<
+ "d_frame_size_bits = " << d_frame_size_bits << "\n" <<
+ "d_out_stream_el_size_bytes = " << d_out_stream_el_size_bytes << "\n" <<
+ "d_n_code_inputs = " << d_n_code_inputs << "\n" <<
+ "d_n_code_outputs = " << d_n_code_outputs << "\n" <<
+ "d_do_streaming = " <<
+ ((d_do_streaming == true) ? "true" : "false") << "\n" <<
+ "d_do_termination = " <<
+ ((d_do_termination == true) ? "true" : "false") << "\n" <<
+ "d_do_mux_inputs = " <<
+ ((d_do_mux_inputs == true) ? "true" : "false") << "\n" <<
+ "d_max_memory = " << d_max_memory << "\n" <<
+ "d_n_states = " << d_n_states << "\n" <<
+ "d_n_input_combinations = " << d_n_input_combinations << "\n";
+#endif
+
+// leave the output multiple at 1 (element); will save any incomplete
+// output data (int's) in "d_save_buffer"; all input data will be consumed
+
+// create the correct input signature
+ int t_n_input_streams = ((d_do_mux_inputs == true) ?
+ 1 : n_code_outputs);
+
+ set_input_signature (gr_make_io_signature (t_n_input_streams,
+ t_n_input_streams,
+ sizeof (float)));
+// create the correct output signature
+ set_output_signature (gr_make_io_signature (n_code_inputs,
+ n_code_inputs,
+ d_out_stream_el_size_bytes));
+#if DO_PRINT_DEBUG_INST_0
+ std::cout <<
+ "input_signature = [" << t_n_input_streams << ", " <<
+ t_n_input_streams << ", " << sizeof (float) << "]\n" <<
+ "output_signature = [" << n_code_outputs << ", " <<
+ n_code_outputs << ", " << d_out_stream_el_size_bytes << "]\n";
+#endif
+
+// always start the fsm in the "init" state
+ d_fsm = fsm_dec_init;
+
+// create a vector of indexes to states when doing "up" or "termination";
+ d_up_term_states_ndx[0] = new size_t [d_n_states];
+ d_up_term_states_ndx[1] = new size_t [d_n_states];
+
+// create the traceback buffers
+// get the total number of out bits per stream
+ d_n_total_input_bits_per_stream = d_frame_size_bits;
+ if (d_do_termination == true)
+ d_n_total_input_bits_per_stream += d_max_memory;
+ d_n_traceback_els = d_n_total_input_bits_per_stream + 1;
+// create the output buffers:
+// this is a 2d matrix structure, where the first dimension
+// is the number of output bits; the second dimension is
+// the number of states.
+// When doing full frames (no tau), each bit-time's state's traceback
+// contains just the pointer to the previous bit-time's state's traceback
+// as well as the inputs for that connection.
+// No further work is required because each reverse-path is unique
+// once a given end-bit-time's state is determined to be "the one"
+ traceback_t_hdl t_out_buf =
+ d_out_buf = new traceback_t_ptr [d_n_traceback_els];
+ for (size_t n = d_n_traceback_els; n > 0; n--) {
+ (*t_out_buf++) = new traceback_t [d_n_states];
+ }
+
+ // create the save buffers
+ char** t_save_buffer = d_save_buffer = new char* [d_n_code_inputs];
+ size_t t_n_out_bytes = ((d_frame_size_bits / g_num_bits_per_byte) +
+ ((d_frame_size_bits % g_num_bits_per_byte) ? 1 : 0));
+ for (size_t n = 0; n < d_n_code_inputs; n++) {
+ (*t_save_buffer++) = new char [t_n_out_bytes];
+ }
+
+// reset the number of saved bits
+ d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
+
+// setup the internal structures for exiting and entering states
+
+#if DO_PRINT_DEBUG_INST_0
+ std::cout <<
+ "d_n_total in bits / stream = " << d_n_total_input_bits_per_stream << "\n"
<<
+ "d_n_traceback_els = " << d_n_traceback_els << "\n" <<
+ "t_n_out_bytes / stream = " << t_n_out_bytes << "\n";
+#endif
+
+// Find the approximate output rate / input rate
+// each input item produces 1 bit of an output item w/o termination
+ double t_rel_rate = (double)(d_out_stream_el_size_bytes *
g_num_bits_per_byte);
+ if (d_do_termination == true) {
+// include termination bits
+ t_rel_rate *= (((double) d_frame_size_bits) /
+ ((double) d_n_total_input_bits_per_stream));
+ }
+// Set the approximate output rate / input rate
+ set_relative_rate (t_rel_rate);
+
+// 'new' everything first; no connections yet
+ state_t_ptr t_state = d_states[0] = new state_t [d_n_states];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections
+ = new connection_t [d_n_input_combinations];
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ t_connection->d_output_bits = new float [d_n_code_outputs];
+ }
+ }
+
+// 'new' everything first; no connections yet
+ t_state = d_states[1] = new state_t [d_n_states];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections
+ = new connection_t [d_n_input_combinations];
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ t_connection->d_output_bits = new float [d_n_code_outputs];
+ }
+ }
+
+// temporary memory and mask for output bit computations
+ size_t t_memory[d_n_code_inputs];
+ size_t t_memory_mask = ((2 << d_max_memory) - 1) ^ 1;
+
+#if DO_PRINT_DEBUG
+ size_t t_state_print_bits = (d_max_memory * d_n_code_inputs) + 1;
+ size_t t_mem_print_bits = d_max_memory + 2;
+
+ std::cout << "Setting States and Connections\n";
+#endif
+
+// loop over all possible memory states
+ state_t_ptr t_state0 = d_states[0];
+ state_t_ptr t_state1 = d_states[1];
+ for (size_t n = 0; n < d_n_states; n++, t_state0++, t_state1++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "Starting state # " << n << " == " <<
+ n2bs (n, t_state_print_bits) << "\n";
+#endif
+// retrieve the memory values for this state
+// probably a faster way to do this, but since this is
+// executed only upon instantiation, whatever.
+ size_t* t_mem_ptr = t_memory;
+ for (size_t p = 0; p < d_n_code_inputs; p++) {
+ int t_mem = state_get_from (n, p, d_max_memory);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "s_g_f (" <<
+ n2bs (n, t_state_print_bits) << ", " <<
+ p << ", " << d_max_memory << ") => t_m = " <<
+ n2bs (t_mem, t_mem_print_bits) << "\n";
+#endif
+// shift them by 1 (and mask) to make updating for all inputs simple
+ (*t_mem_ptr++) = t_mem << 1;
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "t_m_p[" << p << "] = " <<
+ n2bs (t_mem << 1, t_mem_print_bits) << " == (" <<
+ n2bs (t_mem, t_mem_print_bits) << " << 1)\n";
+#endif
+ }
+
+// loop over all possible input values, 1 bit per input stream
+ connection_t_ptr t_connection0 = t_state0->d_connections;
+ connection_t_ptr t_connection1 = t_state1->d_connections;
+ for (size_t q = 0; q < d_n_input_combinations;
+ q++, t_connection0++, t_connection1++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "Starting inputs " << q << " == " <<
+ n2bs (q, d_n_code_inputs + 1) << "\n";
+#endif
+
+// update memory for this set of inputs
+ t_mem_ptr = t_memory;
+ size_t t_this_input = q;
+
+// loop over all code inputs, and update just the single input bit
+ for (size_t r = d_n_code_inputs; r > 0; r--) {
+ int t_mem = (*t_mem_ptr) & t_memory_mask;
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "t_m = " << n2bs (t_mem, t_mem_print_bits) <<
+ " == " << n2bs (*t_mem_ptr, t_mem_print_bits) <<
+ " & " << n2bs (t_memory_mask, t_mem_print_bits) << "\n";
+#endif
+ (*t_mem_ptr++) = t_mem | (t_this_input & 1);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "t_m_p[" << (d_n_code_inputs - r) << "] = " <<
+ n2bs (t_mem | (t_this_input & 1), t_mem_print_bits) <<
+ " == t_m | " << (t_this_input & 1) << "\n";
+#endif
+ t_this_input >>= 1;
+ }
+
+// got the updated memory for this particular state & inputs
+// recreate the "to" state from the updated memory
+ t_mem_ptr = t_memory;
+ size_t t_out_state = 0;
+ for (size_t p = 0; p < d_n_code_inputs; p++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "s_a_t (" <<
+ n2bs (t_out_state, t_state_print_bits) <<
+ ", " << n2bs (*t_mem_ptr, t_mem_print_bits) << ", " << p <<
+ ", " << d_max_memory << ") ==> t_o_s out = ";
+#endif
+ state_add_to (t_out_state, *t_mem_ptr++, p, d_max_memory);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << n2bs (t_out_state, t_state_print_bits) << "\n";
+#endif
+ }
+
+// get the "to" state pointers from d_states[0] to [1]
+ state_t_ptr t_to_state = &(d_states[1][t_out_state]);
+ t_connection0->d_to = t_to_state;
+ t_connection0->d_to_ndx = t_out_state;
+ float* t_output_bit0 = t_connection0->d_output_bits;
+
+// get the "to" state pointers from d_states[1] to [0]
+ t_to_state = &(d_states[0][t_out_state]);
+ t_connection1->d_to = t_to_state;
+ t_connection1->d_to_ndx = t_out_state;
+ float* t_output_bit1 = t_connection1->d_output_bits;
+
+// determine the ideal output values: loop over all outputs
+ size_t t_vec_ctr = 0;
+ for (size_t s = 0; s < d_n_code_outputs; s++) {
+
+// loop over all inputs, xor'ing the result each time
+ int t_out_result = 0;
+ t_mem_ptr = t_memory;
+ for (size_t t = 0; t < d_n_code_inputs; t++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "b_i = " << n2bs (t_out_result, t_mem_print_bits) <<
+ ", st[" << t << "] = " << n2bs ((*t_mem_ptr), t_mem_print_bits) <<
+ ", cg[" << t_vec_ctr << "] = " <<
+ n2bs (d_code_generators[t_vec_ctr], t_mem_print_bits) <<
+ ", st[] & cg[] = " << n2bs ((*t_mem_ptr) &
+ d_code_generators[t_vec_ctr],
+ t_mem_print_bits);
+#endif
+ t_out_result ^= ((*t_mem_ptr++) &
+ d_code_generators[t_vec_ctr++]);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << ", b_o = " <<
+ n2bs (t_out_result, t_mem_print_bits) << '\n';
+#endif
+ }
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "b_r = " << n2bs (t_out_result, t_mem_print_bits);
+#endif
+// sum the number of set bits, mod 2, for the output bit
+ size_t t_out_bit = t_out_result & 1;
+ for (size_t v = d_max_memory; v > 0; v--) {
+ t_out_result >>= 1;
+ t_out_bit ^= (t_out_result & 1);
+ }
+
+// store the result for this particular output stream,
+// converting the bit 1 -> +1.0, and 0 -> -1.0
+ float t_out_value = (float)(((int)(t_out_bit << 1)) - 1);
+ *t_output_bit0++ = t_out_value;
+ *t_output_bit1++ = t_out_value;
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << ", o_v = " << t_out_value << "\n";
+#endif
+
+// finished (for) all output values
+ }
+// finished (for) over all possible input values
+ }
+// finished (for) over all possible states
+ }
+
+// so now d_states is/are completely populated!
+// These make for simple access to looping over all possible inputs or
+// outputs for a given state to determine what the path with the best
+// metric is.
+
+#if DO_PRINT_DEBUG_INST_2
+// loop over all possible memory states
+ std::cout << "State Tables\n";
+ t_state0 = d_states[0];
+ t_state1 = d_states[1];
+ for (size_t n = 0; n < d_n_states; n++, t_state0++, t_state1++) {
+ std::cout << "d_s[0][" << n << "] = " << t_state0 << "\n";
+// loop over all possible input values, 1 bit per input stream
+ connection_t_ptr t_connection0 = t_state0->d_connections;
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection0++) {
+ std::cout << "s0[" << n2bs (n, t_state_print_bits) << "][" <<
+ n2bs (q, d_n_code_inputs+1) << "] = " << t_connection0 <<
+ " -> s1[" << n2bs (t_connection0->d_to_ndx, t_state_print_bits) <<
+ "] = " << t_connection0->d_to << "\n";
+ }
+ std::cout << "d_s[1][" << n << "] = " << t_state1 << "\n";
+ connection_t_ptr t_connection1 = t_state1->d_connections;
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection1++) {
+ std::cout << "s1[" << n2bs (n, t_state_print_bits) << "][" <<
+ n2bs (q, d_n_code_inputs+1) << "] = " << t_connection1 <<
+ " -> s0[" << n2bs (t_connection1->d_to_ndx, t_state_print_bits) <<
+ "] = " << t_connection1->d_to << "\n";
+ }
+ }
+
+ traceback_t_hdl t_out_bufs = d_out_buf;
+ for (size_t n = 0; n < d_n_traceback_els; n++, *t_out_bufs++) {
+ traceback_t_ptr t_out_buf = *t_out_bufs;
+ for (size_t m = 0; m < d_n_states; m++, t_out_buf++) {
+ std::cout << "tb[" << n << "] = " << t_out_bufs <<
+ ", &tb[" << n << "][" << m << "] = " << (&d_out_buf[n][m]) <<
+ ", tb[" << n << "," << m << "] = " << t_out_buf << "\n";
+ }
+ }
+
+ std::cout << "Done with instantiation.\n";
+#endif
+}
+
+gr_decoder_viterbi_block_soft_full::~gr_decoder_viterbi_block_soft_full
+()
+{
+// reverse over from allocation
+
+ delete [] d_up_term_states_ndx[0];
+ delete [] d_up_term_states_ndx[1];
+
+// delete the state's structures
+ state_t_ptr t_state = d_states[0];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections;
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ delete [] t_connection->d_output_bits;
+ }
+ delete [] t_state->d_connections;
+ }
+ delete [] d_states[0];
+
+ t_state = d_states[1];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections;
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ delete [] t_connection->d_output_bits;
+ }
+ delete [] t_state->d_connections;
+ }
+ delete [] d_states[1];
+
+// delete the save buffer
+ char** t_save_buffer = d_save_buffer;
+ for (size_t n = 0; n < d_n_code_inputs; n++) {
+ delete [] (*t_save_buffer++);
+ }
+ delete [] d_save_buffer;
+
+// delete the output buffer
+ traceback_t_hdl t_out_buf = d_out_buf;
+ for (size_t n = d_n_traceback_els; n > 0; n--) {
+ delete [] (*t_out_buf++);
+ }
+ delete [] d_out_buf;
+}
+
+void gr_decoder_viterbi_block_soft_full::reset_metrics (u_char which)
+{
+ state_t_ptr t_state = d_states[which&1];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ t_state->d_max_metric = -1e10;
+#if 0
+// probably don't need to do these, try removing them later
+ t_state->d_max_state_ndx = 0;
+ t_state->d_max_input = -1;
+#endif
+ }
+}
+
+void gr_decoder_viterbi_block_soft_full::zero_metrics (u_char which)
+{
+ state_t_ptr t_state = d_states[which&1];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ t_state->d_max_metric = 0;
+#if 0
+// probably don't need to do these, try removing them later
+ t_state->d_max_state_ndx = -1;
+ t_state->d_max_input = -1;
+#endif
+ }
+}
+
+void gr_decoder_viterbi_block_soft_full::forecast
+(int noutput_items,
+ gr_vector_int &ninput_items_required)
+{
+ int ninput_items = fixed_rate_noutput_to_ninput (noutput_items);
+
+ int ninputs = ninput_items_required.size();
+ for (int n = 0; n < ninputs; n++)
+ ninput_items_required[n] = ninput_items;
+}
+
+/*
+ * Compute the number of input items (soft symbols [floats]) needed to produce
+ * 'noutput' items (elements). For convolutional decoders, there is 1
+ * bit output per bit input per stream, with the addition of a some
+ * bits for trellis termination if selected. Without termination,
+ * there is exactly 1:1 input to output (1 symbol in to 1 bit out),
+ * no matter the encoding type.
+ *
+ * if (not terminating), then get the number of output bytes.
+ *
+ * otherwise, find the number of frames (not necessarily and integer),
+ * and then compute the number of input bits (including termination)
+ * required to produce those frames. Subtract the number of bits
+ * leftover from the previous computation, then find the number of input
+ * elements (soft symbols), ceil'd to make sure there are enough.
+ *
+ * finally, if the input streams are mux'ed, then multiply by the
+ * number of inputs.
+ */
+
+int
+gr_decoder_viterbi_block_soft_full::fixed_rate_noutput_to_ninput
+(int noutput_items)
+{
+ int t_ninput_items = 0;
+ int t_noutput_bits = (noutput_items * d_out_stream_el_size_bytes *
+ g_num_bits_per_byte) - d_n_saved_bits;
+// if there are enough saved bits, just use those, no inputs required
+ if (t_noutput_bits <= 0)
+ return (t_ninput_items);
+
+// remove any bits already in the decoding trellis
+ if (d_time_count != 0) {
+ int t_time_bits = ((d_time_count > d_frame_size_bits) ? 0 :
+ d_frame_size_bits - d_time_count);
+ t_noutput_bits -= t_time_bits;
+ t_ninput_items += t_time_bits;
+ }
+// if completing this trellis doesn't create enough outputs ...
+ if (t_noutput_bits > 0) {
+
+// there is a 1:1 ratio between input symbols and output bits (per
+// stream), except for termination bits which are already taken into
+// account in the total # of input bits per stream class variable;
+// need to round the # output bits to the
+
+// find the number of frames, ceil'd to the next higher integer
+ int t_nframes = (int) ceilf (((float) t_noutput_bits) /
+ ((float) d_frame_size_bits));
+// find the number of required input bits
+ t_ninput_items += t_nframes * d_n_total_input_bits_per_stream;
+ }
+
+// if doing mux'ing, there are more elements in the single input
+ if (d_do_mux_inputs == true) {
+ t_ninput_items *= d_n_code_outputs;
+ }
+ return (t_ninput_items);
+}
+
+int
+gr_decoder_viterbi_block_soft_full::general_work
+(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+#if DO_TIME_THOUGHPUT
+ struct timeval t_tp;
+ start_timer (&t_tp);
+#endif
+#if DO_PRINT_DEBUG
+ size_t t_state_print_bits = (d_max_memory * d_n_code_inputs) + 1;
+ size_t t_mem_print_bits = d_max_memory + 2;
+#endif
+// setup variables for quicker access
+ const float **in_buf = (const float **) &input_items[0];
+ char **out_buf = (char **) &output_items[0];
+ int t_in_buf_ndx = 0, t_out_buf_ndx = 0;
+ int t_out_bit_shift = 0;
+ int t_ninput_items = fixed_rate_noutput_to_ninput (noutput_items);
+ int t_noutput_bytes = noutput_items * d_out_stream_el_size_bytes;
+
+#if DO_PRINT_DEBUG_INST
+ std::cout << "# output items = " << noutput_items << " (" <<
+ t_noutput_bytes << " Bytes, " << (t_noutput_bytes * g_num_bits_per_byte) <<
+ " bits), # input items = " << t_ninput_items << " Symbols\n";
+ for (size_t n = 0; n < ninput_items.size(); n++) {
+ std::cout << "# input items [" << n << "] = " << ninput_items[n] << "\n";
+ }
+#endif
+
+// put any leftover bits into the output
+ if (d_n_saved_bits != 0) {
+// copy the leftover from the save buffer
+// check to make sure it will all fit
+ size_t t_noutput_bits = t_noutput_bytes * g_num_bits_per_byte;
+ size_t t_n_copy;
+ if (t_noutput_bits < d_n_saved_bits) {
+// asking for fewer bits than available; set to copy
+// just what's being asked for
+ t_n_copy = t_noutput_bytes;
+ } else {
+// asking for at least as many bits as available; set to copy all
+ t_out_buf_ndx = d_n_saved_bits / g_num_bits_per_byte;
+ t_out_bit_shift = d_n_saved_bits % g_num_bits_per_byte;
+ t_n_copy = t_out_buf_ndx + (t_out_bit_shift != 0 ? 1 : 0);
+ }
+// do the copy for all output streams (code inputs)
+// copy starting at save buffer index "start"
+ for (size_t n = 0; n < d_n_code_inputs; n++)
+ bcopy (&(d_save_buffer[n][d_n_saved_bits_start_ndx]),
+ out_buf[n], t_n_copy);
+#if DO_PRINT_DEBUG_INST
+ std::cout << "Copied " << t_n_copy << " Byte" <<
+ (t_n_copy != 1 ? "s" : "") << ": s_b[][" <<
+ d_n_saved_bits_start_ndx << "] => o_b[][0]\n" <<
+ "# saved bits = " << d_n_saved_bits <<
+ ", o_b_ndx = " << t_out_buf_ndx <<
+ ", bit shift = " << t_out_bit_shift << "\n";
+#endif
+// update the number of saved bits and start
+ if (t_noutput_bits < d_n_saved_bits) {
+// asking for fewer bit than available: update
+// the number of saved bits and their starting index
+ d_n_saved_bits_start_ndx += t_noutput_bytes;
+ d_n_saved_bits -= (t_noutput_bytes * g_num_bits_per_byte);
+#if DO_PRINT_DEBUG_INST
+ std::cout << "Updated # saved bits = " << d_n_saved_bits <<
+ ", index = " << d_n_saved_bits_start_ndx << "\n";
+#endif
+// nothing to consume; return the desired number of output items
+ return (noutput_items);
+ } else {
+ d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
+ }
+ }
+#if DO_PRINT_DEBUG_INST
+ std::cout << "Starting FSM in state: " <<
+ (d_fsm == fsm_dec_init ? "init" :
+ (d_fsm == fsm_dec_doing_up ? "up" :
+ (d_fsm == fsm_dec_doing_middle ? "middle" :
+ (d_fsm == fsm_dec_doing_term ? "term" :
+ (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "\n";
+#endif
+
+// while there are input items to create
+ while (t_out_buf_ndx < t_noutput_bytes) {
+#if DO_PRINT_DEBUG_FMS
+ std::cout << "Starting 'while': processing " << t_in_buf_ndx << " of " <<
+ t_ninput_items << " items.\nJumping to state '" <<
+ (d_fsm == fsm_dec_init ? "init" :
+ (d_fsm == fsm_dec_doing_up ? "up" :
+ (d_fsm == fsm_dec_doing_middle ? "middle" :
+ (d_fsm == fsm_dec_doing_term ? "term" :
+ (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "'\n";
+#endif
+// jump to the correct state in the fsm
+ switch (d_fsm) {
+ case fsm_dec_doing_up:
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Starting fsm_dec_doing_up\n";
+#endif
+// set the number of up_down indices
+ size_t t_n_up_down_ndx = 1 << (d_n_code_inputs *
+ d_time_count);
+// stay in this state until the correct number of input symbols are
+// reached; exit also if we run out of input symbols to process
+ while ((d_time_count < d_max_memory) &
+ (t_in_buf_ndx < t_ninput_items)) {
+#if DO_PRINT_DEBUG_UP_0
+ std::cout << "Doing 'while' loop:\n" <<
+ "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" <<
+ "d_time_count = " << d_time_count << "\n" <<
+ "d_max_memory = " << d_max_memory << "\n" <<
+ "t_in_buf_ndx = " << t_in_buf_ndx << "\n" <<
+ "t_ninput_items = " << t_ninput_items << "\n";
+#endif
+// use the "from" states, loop over all inputs and compute the metric for
+// each & store it in the "to" state at the end of the connection.
+// no need to compare metrics yet, since none join into any given state
+
+#if 0
+// reset the "to" state's metrics
+// probably don't need to do this; try removing later
+ reset_metrics (d_states_ndx ^ 1);
+#if DO_PRINT_DEBUG_UP
+ std::cout << "Reset Metrics\n";
+#endif
+#endif
+
+// reset the state's index for each set of new inputs
+ size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+ size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
+// loop over all current stored "up" states
+ for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+ size_t t_state_ndx = *t_state_ndx_ptr++;
+// get a pointer to this state's structure
+ state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// get the connections for all inputs
+ connection_t_ptr t_connection = t_state->d_connections;
+#if DO_PRINT_DEBUG_UP_0
+ std::cout << "Looping over all 'up' states:\n" <<
+ "n = " << n << "\n" <<
+ "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" <<
+ "d_states_ndx = " << d_states_ndx << "\n" <<
+ "t_state_ndx = " << t_state_ndx << "\n" <<
+ "d_n_input_combs = " << d_n_input_combinations << "\n" <<
+ "t_state = " << t_state << "\n" <<
+ "t_connection = " << t_connection << "\n";
+#endif
+// loop over all possible input values, 1 bit per input stream
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
+// find the "to" state for this connection
+ state_t_ptr t_to_state = t_connection->d_to;
+// get the output bits for this connection
+ float* t_output_bit = t_connection->d_output_bits;
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+#if DO_PRINT_DEBUG_UP_0
+ std::cout <<
+ "to state index = " << t_connection->d_to_ndx << "\n" <<
+ "current metric = " << t_metric << "\n";
+#endif
+ if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+ const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+ for (size_t r = d_n_code_outputs; r > 0; r--) {
+#if DO_PRINT_DEBUG_UP
+ std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
+ *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += ((*t_in_buf++) * (*t_output_bit++));
+#if DO_PRINT_DEBUG_UP
+ std::cout << t_metric << "\n";
+#endif
+ }
+ } else {
+// loop over all encoder-output values
+ for (size_t r = 0; r < d_n_code_outputs; r++) {
+#if DO_PRINT_DEBUG_UP
+ std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
+ ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+#if DO_PRINT_DEBUG_UP
+ std::cout << t_metric << "\n";
+#endif
+ }
+ }
+// get the "to" state index
+ size_t t_to_ndx = t_connection->d_to_ndx;
+// store the metric in the "to" state; should not have been used before
+ t_to_state->d_max_metric = t_metric;
+// add the "to" state index to the "up" state list
+ *t_next_state_ndx_ptr++ = t_to_ndx;
+// update the traceback structure, depending on which variety it is
+// doing full trellis before decoding; use d_out_buf
+// simple: get the current state & output state
+ traceback_t_ptr t_out_buf = &(d_out_buf[d_time_count]
+ [t_state_ndx]);
+ traceback_t_ptr t_next_out_buf = &(d_out_buf[d_time_count+1]
+ [t_to_ndx]);
+#if DO_PRINT_DEBUG_UP_1
+ std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n" <<
+ "ndx[" << n << "] == " << t_state_ndx <<
+ ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+ "]: max_ndx = " <<
+ n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+ ", input = " << n2bs(q, d_n_code_inputs+1) <<
+ ": " << t_next_out_buf << " => " << t_out_buf << "\n";
+#endif
+// and connect output to the current, set inputs on output
+ t_next_out_buf->d_prev = t_out_buf;
+ t_next_out_buf->d_inputs = q;
+// finished (for) this input value
+ }
+// finished (for) this "up_term" state
+ }
+// increment the in_buf index, depending on mux'ing or not
+ t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counter
+ d_time_count++;
+// update the number of "up_term" states
+ d_up_term_ndx ^= 1;
+// increase the number of using states
+ t_n_up_down_ndx <<= d_n_code_inputs;
+// change which d_states' index to use as starting
+ d_states_ndx ^= 1;
+// finished (while) staying in this fsm state or not
+ }
+// if reached the end of doing the "up" part of the trellis,
+// switch states into the middle
+ if (d_time_count == d_max_memory) {
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Setting FSM to fsm_dec_doing_middle\n";
+#endif
+ d_fsm = fsm_dec_doing_middle;
+ }
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_doing_up\n";
+#endif
+ break;
+ case (fsm_dec_doing_middle):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_doing_middle\n";
+#endif
+// stay in this state until the correct number of input symbols is
+// reached (if doing block coding), or until there are no more input
+// symbols to parse
+ while (((d_frame_size_bits != 0) &
+ (d_time_count < d_frame_size_bits) &
+ (t_in_buf_ndx < t_ninput_items)) |
+ ((d_frame_size_bits == 0) &
+ (t_in_buf_ndx < t_ninput_items))) {
+// use all states, loop over all inputs, compute the metric for
+// each; compare the current metric with all previous stored metric in the
+// endpoint of the connection to find the highest one.
+
+// reset the "to" state's metrics
+ reset_metrics (d_states_ndx ^ 1);
+// get the state's index for each set of new inputs
+ state_t_ptr t_state = d_states[d_states_ndx];
+#if DO_PRINT_DEBUG_MIDDLE
+ std::cout << "Time Count " << (d_time_count+1) << " of " <<
+ d_frame_size_bits << "\n" <<
+ "d_states_ndx = " << d_states_ndx << "\n";;
+#endif
+// loop over all current states
+ for (size_t n = 0; n < d_n_states; n++, t_state++) {
+// loop over all possible input values, 1 bit per input stream
+ connection_t_ptr t_connection = t_state->d_connections;
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "Looping over all 'middle' states: " <<
+ n << " of " << d_n_states << "\n";
+#endif
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "Input = " << n2bs(q, d_n_code_inputs+1) << "\n";
+#endif
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+// get the "to" state
+ state_t_ptr t_to_state = t_connection->d_to;
+// get that state's metric
+ float t_to_metric = t_to_state->d_max_metric;
+// see if the computation is even needed;
+// maximum change is d_n_code_outputs if all bits match exactly
+ if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "!not computing metric!\n";
+#endif
+ continue;
+ }
+// metrics are close enough; do the computation and the compare
+// get the output bits for this connection
+ float* t_output_bit = t_connection->d_output_bits;
+ if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+ const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+ for (size_t r = d_n_code_outputs; r > 0; r--) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
+ *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += ((*t_in_buf++) * (*t_output_bit++));
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << t_metric << "\n";
+#endif
+ }
+ } else {
+// loop over all encoder-output values
+ for (size_t r = 0; r < d_n_code_outputs; r++) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
+ ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << t_metric << "\n";
+#endif
+ }
+ }
+// done with this input value; compare old and new metrics
+ if (t_metric > t_to_metric) {
+#if DO_PRINT_DEBUG_MIDDLE
+ std::cout << "New Metric to s[" <<
+ n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
+ if (t_to_state->d_max_metric == -1e10) {
+ std::cout << "setting to ";
+ } else {
+ std::cout << "was s[" <<
+ n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
+ "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
+ "]@ " << t_to_state->d_max_metric << " now ";
+ }
+ std::cout << "s[" << n2bs(n,t_state_print_bits) << "] i[" <<
+ n2bs (q, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
+#endif
+// new metric is better; copy that info into the "to" state
+ t_to_state->d_max_metric = t_metric;
+ t_to_state->d_max_state_ndx = n;
+ t_to_state->d_max_input = q;
+ }
+// finished (for) this input value
+ }
+// finished (for) this state
+ }
+// done with all states and all inputs; now update the traceback structure
+// change which d_states' index to use as starting
+ d_states_ndx ^= 1;
+// get the state's index for the "to" set of new inputs to get the
+// "max" stuff from
+ t_state = d_states[d_states_ndx];
+// update the traceback structure
+// loop over all current states
+ traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
+ traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
+#if DO_PRINT_DEBUG_MIDDLE_1
+ std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
+#endif
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+// simple: get the current state & output state
+// and connect output to the current, set inputs on output
+ traceback_t_ptr t_out_buf = t_out_bufs++;
+ traceback_t_ptr t_prev_out_buf =
+ &(t_prev_out_bufs[t_state->d_max_state_ndx]);
+#if DO_PRINT_DEBUG_MIDDLE_1
+ std::cout << "s[" << n2bs(d_n_states-n,t_state_print_bits) <<
+ "]: max_ndx = " <<
+ n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+ ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
+ ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
+#endif
+ t_out_buf->d_prev = t_prev_out_buf;
+ t_out_buf->d_inputs = t_state->d_max_input;
+// finished doing this state
+ }
+// increment the in_buf index, depending on mux'ing or not
+ t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counter
+ d_time_count++;
+// finished (while) staying in this fsm state or not
+ }
+ if ((d_frame_size_bits != 0) &
+ (d_time_count == d_frame_size_bits)) {
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Setting FSM to fsm_dec_doing_term\n";
+#endif
+ d_fsm = fsm_dec_doing_term;
+ }
+ break;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_doing_middle\n";
+#endif
+ case (fsm_dec_doing_term):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_doing_term\n";
+#endif
+// set the "next" up_down index to the end of their states
+ size_t t_time_count = d_max_memory - (d_time_count - d_frame_size_bits);
+ t_n_up_down_ndx = 1 << (d_n_code_inputs * t_time_count);
+// stay in this state until the correct number of input symbols are
+// reached; exit also if we run out of input symbols to process
+ while ((t_time_count > 0) &
+ (t_in_buf_ndx < t_ninput_items)) {
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "Doing time " << (d_max_memory - t_time_count + 1) <<
+ " of " << d_max_memory << "; starting buf[" << t_in_buf_ndx <<
+ "] of [" << t_ninput_items << "]\n";
+#endif
+// use the "to" states,
+// FIXME: loop over just the "0" inputs
+// and compute the metric for
+// each, compare & store it in the "to" state at the end of the connection.
+
+// reset the "to" state's metrics
+ reset_metrics (d_states_ndx ^ 1);
+// reset the state's index for each set of new inputs
+ size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+ size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
+// loop over all current stored "term" state indeces
+ for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+ size_t t_state_ndx = *t_state_ndx_ptr++;
+ state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// loop over just the all 0 input value (d_connections[0])
+ connection_t_ptr t_connection = t_state->d_connections;
+// get the "to" state
+ state_t_ptr t_to_state = t_connection->d_to;
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+// get that state's metric
+ float t_to_metric = t_to_state->d_max_metric;
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "Term state " << (n+1) << " of " << t_n_up_down_ndx <<
+ "; using d_s[" << d_states_ndx << "][" <<
+ n2bs(t_state_ndx,t_state_print_bits) << "]\n";
+#endif
+// see if the computation is even needed;
+// maximum change is d_n_code_outputs if all bits match exactly
+ if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "!not computing metric!\n";
+#endif
+ continue;
+ }
+// metrics are close enough; do the computation and the compare
+// get the output bits for this connection
+ float* t_output_bit = t_connection->d_output_bits;
+ if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+ const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+ for (size_t r = d_n_code_outputs; r > 0; r--) {
+ t_metric += ((*t_in_buf++) * (*t_output_bit++));
+ }
+ } else {
+// loop over all encoder-output values
+ for (size_t r = 0; r < d_n_code_outputs; r++) {
+ t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+ }
+ }
+// done with this input value; compare old and new metrics
+// see if it's the best metric
+ if (t_metric > t_to_metric) {
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "New Metric to s[" <<
+ n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
+ if (t_to_state->d_max_metric == -1e10) {
+ std::cout << "setting to ";
+ } else {
+ std::cout << "was s[" <<
+ n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
+ "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
+ "]@ " << t_to_state->d_max_metric << " now ";
+ }
+ std::cout << "s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+ "] i[" << n2bs (0, d_n_code_inputs+1) << "]@ " << t_metric <<
"\n";
+#endif
+ t_to_state->d_max_metric = t_metric;
+ t_to_state->d_max_state_ndx = t_state_ndx;
+ t_to_state->d_max_input = 0;
+ }
+// add the "to" state's index to the "next" set of state's indices list
+ *t_next_state_ndx_ptr++ = t_connection->d_to_ndx;
+// finished (for) this state
+ }
+// done with all states and all inputs; now update the traceback structure
+// change which d_states' index to use as starting
+ d_states_ndx ^= 1;
+// update the number of "up_term" states
+ d_up_term_ndx ^= 1;
+// reduce the number of using states
+ t_n_up_down_ndx >>= d_n_code_inputs;
+// reset the state's index for each set of new inputs
+ t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+// update the traceback structure
+// loop over all current states
+ traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
+ traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
+#if DO_PRINT_DEBUG_TERM_1
+ std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
+#endif
+// loop over all current stored "term" state indices
+ for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+// get the start index and then pointer to each of the "to" states,
+// which hold the newest "max" stuff
+ size_t t_state_ndx = *t_state_ndx_ptr++;
+ state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// simple: get the current state & output state
+// and connect output to the current, set inputs on output
+ traceback_t_ptr t_out_buf = &(t_out_bufs[t_state_ndx]);
+ traceback_t_ptr t_prev_out_buf =
+ &(t_prev_out_bufs[t_state->d_max_state_ndx]);
+#if DO_PRINT_DEBUG_TERM_1
+ std::cout << "ndx[" << n << "] == " << t_state_ndx <<
+ ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+ "]: max_ndx = " <<
+ n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+ ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
+ ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
+#endif
+ t_out_buf->d_prev = t_prev_out_buf;
+ t_out_buf->d_inputs = t_state->d_max_input;
+// finished (for) this state
+ }
+// increment the in_buf index, depending on mux'ing or not
+ t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counters
+ t_time_count--;
+ d_time_count++;
+// finished (while) staying in this fsm state or not
+ }
+ if (t_time_count == 0) {
+// finished this trellis, now move as much of the decoded input to the
+// output buffer as possible
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Setting FSM to fsm_dec_output\n";
+#endif
+ d_fsm = fsm_dec_output;
+ }
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_doing_term\n";
+#endif
+ break;
+ case (fsm_dec_output):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_output.\n";
+#endif
+// this is done in reverse bit order (last time to first time)
+// using the traceback structure in d_out_buf, starting with
+// the maximum valued one in the last time slot, then using
+// the traceback's "d_prev" link to trace the trellis back
+
+// see where the output data will terminate
+ int t_next_out_buf_ndx = (t_out_buf_ndx +
+ (d_frame_size_bits / g_num_bits_per_byte));
+ int t_next_out_bit_shift = (t_out_bit_shift +
+ (d_frame_size_bits % g_num_bits_per_byte));
+ if (t_next_out_bit_shift >= g_num_bits_per_byte) {
+ t_next_out_bit_shift -= g_num_bits_per_byte;
+ t_next_out_buf_ndx++;
+ }
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "First bit in at out[][" << t_out_buf_ndx << "].[" <<
+ t_out_bit_shift << "] -> " << d_frame_size_bits << " bits == " <<
+ (d_frame_size_bits / g_num_bits_per_byte) << " Byte" <<
+ ((d_frame_size_bits / g_num_bits_per_byte) != 1 ? "s" : "") <<
+ " + " << (d_frame_size_bits % g_num_bits_per_byte) << " bit" <<
+ ((d_frame_size_bits % g_num_bits_per_byte) != 1 ? "s" : "") <<
+ "\nNext set of bits start at out[][" << t_next_out_buf_ndx <<
+ "].[" << t_next_out_bit_shift << "]\n";
+#endif
+// find the starting traceback structure
+ traceback_t_ptr t_out_buf;
+ if (d_do_termination == true) {
+// FIXME: assume termination state == 0
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Using termination; going through trellis for " <<
+ d_max_memory << " bit" <<
+ ((d_max_memory != 1) ? "s" : "") << "\n";
+#endif
+ t_out_buf = &(d_out_buf[d_time_count][0]);
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Starting traceback ptr " << t_out_buf << "\n";
+#endif
+// skip over the termination bits
+ for (size_t n = d_max_memory; n > 0; n--) {
+ t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+ }
+ } else {
+// no termination but doing block coding;
+// FIXME: use the state with the bext metric
+// get the state's index for each set of new inputs
+ state_t_ptr t_state = d_states[d_states_ndx];
+ float t_max_metric = t_state->d_max_metric;
+ size_t t_max_state_ndx = 0;
+ t_state++;
+// loop over all current states
+ for (size_t n = 1; n < d_n_states; n++, t_state++) {
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+// compare with current max
+ if (t_metric > t_max_metric) {
+ t_max_metric = t_metric;
+ t_max_state_ndx = n;
+ }
+ }
+// get the correct out_buf reference to start with
+ t_out_buf = &(d_out_buf[d_time_count][t_max_state_ndx]);
+ }
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "Found starting traceback ptr " << t_out_buf <<
+ "; getting all " << d_frame_size_bits << " bits per stream.\n";
+#endif
+// now we've got the starting traceback structure address;
+// check to make sure there is enough space in each output buffer
+ size_t t_frame_bit_ndx = d_frame_size_bits;
+ if ((t_next_out_buf_ndx > t_noutput_bytes) |
+ ((t_next_out_buf_ndx == t_noutput_bytes) &
+ (t_next_out_bit_shift != 0))) {
+// not enough space for all output bits;
+// find the number of extra bits to save
+ size_t t_save_buf_ndx = t_next_out_buf_ndx - t_noutput_bytes;
+ size_t t_n_extra_bits = ((t_save_buf_ndx * g_num_bits_per_byte) +
+ t_next_out_bit_shift);
+// set the number of saved bits
+ d_n_saved_bits = t_n_extra_bits;
+// remove the extra bits from the number to copy to the output buffer
+ t_frame_bit_ndx -= t_n_extra_bits;
+// find the actual output buf index, once we get there
+ t_next_out_buf_ndx -= t_save_buf_ndx;
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "Not enough output buffer space:\n" <<
+ "len (o_b) = " << t_noutput_bytes << " ==> " <<
+ t_n_extra_bits << " extra bit" <<
+ (t_n_extra_bits != 1 ? "s" : "") << " == " <<
+ t_save_buf_ndx << " Byte" <<
+ (t_save_buf_ndx != 1 ? "s" : "") << ", " <<
+ t_next_out_bit_shift << " bit" <<
+ (t_next_out_bit_shift != 1 ? "s" : "") << "\n";
+#endif
+// zero each output buffers' bytes
+ size_t t_n_zero = t_save_buf_ndx + (t_next_out_bit_shift ? 1 : 0);
+#if DO_PRINT_DEBUG_OUTPUT
+ size_t t_n_out_bytes = ((d_frame_size_bits / g_num_bits_per_byte) +
+ ((d_frame_size_bits % g_num_bits_per_byte) ? 1
: 0));
+ std::cout << "Zeroing save buffer from for " << t_n_zero <<
+ " Byte" << (t_n_zero != 1 ? "s" : "") << " (of " <<
+ d_frame_size_bits << " bit" <<
+ (d_frame_size_bits != 1 ? "s" : "") << " == " << t_n_out_bytes <<
+ " Byte" << (t_n_out_bytes != 1 ? "s" : "") << ")\n";
+#endif
+ for (size_t m = 0; m < d_n_code_inputs; m++)
+ bzero (d_save_buffer[m], t_n_zero);
+// loop over all extra bits
+ for (size_t n = t_n_extra_bits; n > 0; n--) {
+// first decrement the output bit & byte as necessary
+ if (--t_next_out_bit_shift < 0) {
+ t_next_out_bit_shift += g_num_bits_per_byte;
+ t_save_buf_ndx--;
+ }
+// get the encoder inputs to output
+ size_t t_inputs = t_out_buf->d_inputs;
+// loop over all code inputs (decoder-outputs), 1 bit per stream
+ for (size_t m = 0; m < d_n_code_inputs; m++) {
+ d_save_buffer[m][t_save_buf_ndx] |=
+ ((t_inputs & 1) << t_next_out_bit_shift);
+ t_inputs >>= 1;
+ }
+ t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+ }
+// at exit, "t_out_buf_ndx" should be == t_noutput_bytes, and
+// "t_out_bit_shift" should be 0; check these!
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "n_o_b_ndx (" << t_next_out_buf_ndx << ") ?=? " <<
+ "#o_B (" << t_noutput_bytes << ") & t_o_b_sh (" <<
+ t_next_out_bit_shift << ") ?=? 0\n";
+ assert (t_next_out_buf_ndx == t_noutput_bytes);
+ assert (t_next_out_bit_shift == 0);
+#endif
+ }
+// set the correct output buffer index and bit shift
+ t_out_bit_shift = t_next_out_bit_shift;
+ t_out_buf_ndx = t_next_out_buf_ndx;
+// copy any remaining bits looping backwards in bit-time
+// through the traceback trellis
+ for (size_t n = t_frame_bit_ndx; n > 0; n--) {
+// first decrement the output bit & byte as necessary
+ if (--t_out_bit_shift < 0) {
+ t_out_bit_shift += g_num_bits_per_byte;
+ t_out_buf_ndx--;
+ }
+// get the encoder inputs to output
+ size_t t_inputs = t_out_buf->d_inputs;
+// loop over all code inputs (decoder-outputs), 1 bit per stream
+ for (size_t m = 0; m < d_n_code_inputs; m++) {
+ out_buf[m][t_out_buf_ndx] |= ((t_inputs & 1) << t_out_bit_shift);
+ t_inputs >>= 1;
+ }
+ t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+ }
+// set the next output byte and bit-shift
+ t_out_bit_shift = t_next_out_bit_shift;
+ t_out_buf_ndx = t_next_out_buf_ndx;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Set FSM to fsm_dec_init\n";
+#endif
+ d_fsm = fsm_dec_init;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_output\n";
+#endif
+ break;
+ case (fsm_dec_init):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_init\n";
+#endif
+// this is called immediately (first input bit upon startup),
+// or after termination of a trellis.
+
+// reset states to the 0'th one
+ d_up_term_ndx = d_states_ndx = 0;
+// zero the metrics for those states
+ zero_metrics (0);
+#if 0
+// might not need to do this; check and see after it works
+// reset up_term states and number so that there is 1 item, the "0" state.
+ bzero (d_up_term_states_ndx[0], sizeof (size_t) * d_n_states);
+ bzero (d_up_term_states_ndx[1], sizeof (size_t) * d_n_states);
+#else
+ d_up_term_states_ndx[0][0] = 0;
+#endif
+// reset time count back to the start
+ d_time_count = 0;
+#if 0
+// reset the traceback structures
+// might not need to do this; check and see after it works
+ traceback_t_hdl t_out_bufs = d_out_buf;
+ for (size_t n = d_n_traceback_els; n > 0; n--) {
+ traceback_t_ptr t_out_buf = (*t_out_bufs++);
+ for (size_t m = d_n_states; m > 0; m--, t_out_buf++) {
+ t_out_buf->d_prev = NULL;
+ t_out_buf->d_inputs = -1;
+ }
+ }
+#endif
+// set the fsm to "doing up"
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Set FSM to fsm_dec_doing_up\n";
+#endif
+ d_fsm = fsm_dec_doing_up;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_init\n";
+#endif
+ break;
+// should never get here!
+ default:
+ assert (0);
+// done (switch) with FSM
+ }
+// done (while) there are inputs
+ }
+
+// consume all of the input items on all input streams
+// "ninput_items[]" doesn't seem to be reliable,
+// so compute this from the actual number of frames processed
+#if DO_PRINT_DEBUG_EXIT
+ std::cout << "Exiting FSM in state: " <<
+ (d_fsm == fsm_dec_init ? "init" :
+ (d_fsm == fsm_dec_doing_up ? "up" :
+ (d_fsm == fsm_dec_doing_middle ? "middle" :
+ (d_fsm == fsm_dec_doing_term ? "term" :
+ (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "\n" <<
+ "Consuming " << t_in_buf_ndx <<
+ " input items on each input stream (of " << t_ninput_items << ").\n";
+#endif
+ consume_each (t_in_buf_ndx);
+
+// make sure the number of output items makes sense
+// t_out_buf_ndx always points to the current index
+// t_out_bit_shift always points to the next bit position to be written
+ int t_leftover_bytes = t_out_buf_ndx % d_out_stream_el_size_bytes;
+ int t_leftover_bits = ((t_leftover_bytes * g_num_bits_per_byte) +
+ t_out_bit_shift);
+ int t_noutput_items = noutput_items;
+#if DO_PRINT_DEBUG_EXIT
+ std::cout << "Final o_b[" << t_out_buf_ndx << "][" <<
+ t_out_bit_shift << "] of " << t_noutput_bytes <<
+ ", el_size = " << d_out_stream_el_size_bytes <<
+ ", lo_Bytes = " << t_leftover_bytes <<
+ ", t_lo_bits = " << t_leftover_bits << "\n" <<
+ "Desired # output items = " << noutput_items << "\n";
+#endif
+ if (t_leftover_bits != 0) {
+ // should never get here!
+#if 1
+ assert (0);
+#else
+ int t_ndx = t_out_buf_ndx - t_leftover_bytes;
+ size_t t_n_copy = t_leftover_bytes + ((t_out_bit_shift != 0) ? 1 : 0);
+ assert (t_n_copy <= d_out_stream_el_size_bytes);
+// copy the leftover into the save buffer
+ for (size_t n = 0; n < d_n_code_inputs; n++) {
+ bcopy (&(out_buf[n][t_ndx]), d_save_buffer[n], t_n_copy);
+ }
+ t_noutput_items = t_ndx / d_out_stream_el_size_bytes;
+ d_n_saved_bits = t_leftover_bits;
+#if DO_PRINT_DEBUG_EXIT
+ std::cout << "Copied " << t_n_copy << " Byte" <<
+ (t_n_copy != 1 ? "s" : "") << " from o_b[][" << t_ndx <<
+ "] into each save buffer.\n" <<
+ "Actual #output items = " << t_noutput_items <<
+ ", # saved bit(s) = " << d_n_saved_bits << "\n";
+#endif
+#endif
+ }
+
+#if DO_TIME_THOUGHPUT
+ u_long d_t = end_timer (&t_tp);
+
+ std::cout << "dec_blk_conv_soft_full: Completed " << t_ninput_items <<
+ " bits in " << d_t << " usec => " <<
+ 1e6*(((double)(t_ninput_items))/((double) d_t)) <<
+ " b/s\n";
+#endif
+
+// returns number of items written to each output stream
+ return (t_noutput_items);
+}
Index: libecc/decoder_viterbi.h
===================================================================
RCS file: libecc/decoder_viterbi.h
diff -N libecc/decoder_viterbi.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libecc/decoder_viterbi.h 5 Jul 2006 17:49:58 -0000 1.1
@@ -0,0 +1,112 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_DECODER_VITERBI_H
+#define INCLUDED_DECODER_VITERBI_H
+
+#include <vector>
+#include "decoder.h"
+#include "encoder.h"
+
+class decoder_viterbi : public decoder
+{
+public:
+/*!
+ * \brief Decode the incoming metrics streams using the Viterbi algorithm.
+ *
+ * input: streams of metrics, 2 streams per n_code_outputs - one each for
+ * a 0- and 1-bit metric.
+ *
+ * output: streams of char, one stream per n_code_inputs, using only
+ * the right-most justified bit as the single bit per output item.
+ *
+ * sample_precision: precision of the incoming metrics
+ * if == 0, then use soft precision (32 bit float);
+ * otherwise, use an integer up to 32 bits, already sign-extended
+ * to the nearest power-of-2-sized type (char, short, long).
+ *
+ * l_encoder: pointer to an encoder class from which to determine the
+ * trellis transitions (states and i/o bits).
+ */
+
+ decoder_viterbi (int sample_precision,
+ encoder* l_encoder);
+
+ virtual ~decoder_viterbi () {};
+
+protected:
+/*
+ * fsm_dec_viterbi_t: finite state machine for the convolutional decoder;
+ * output happens all the time, so that's built-in to each state.
+ *
+ * fsm_dec_viterbi_init: initialize for a new frame / block; this is already
+ * done at instantiation, so do it only at the end of a block.
+ *
+ * fsm_dec_viterbi_doing_up: encoding at the start of a block
+ *
+ * fsm_dec_viterbi_doing_middle: doing encoding inside the trellis
+ *
+ * fsm_dec_viterbi_doing_term: termination trellis, if requested
+ */
+
+ enum fsm_dec_viterbi_t {
+ fsm_dec_viterbi_init, fsm_dec_viterbi_doing_up,
+ fsm_dec_viterbi_doing_middle, fsm_dec_viterbi_doing_term
+ };
+
+ virtual void decode_private (const char** in_buf, char** out_buf);
+ virtual void decode_loop (const char** in_buf, char** out_buf,
+ size_t* which_counter, size_t how_many);
+ virtual char get_next_input (const char** in_buf, size_t code_input_n);
+ virtual char get_next_input__up (const char** in_buf,
+ size_t code_input_n);
+ virtual char get_next_input__middle (const char** in_buf,
+ size_t code_input_n);
+ virtual char get_next_input__term (size_t code_input_n);
+ virtual void increment_counters (bool while_decoding);
+
+ fsm_dec_viterbi_t d_fsm_state;
+ bool d_do_streaming, d_do_termination;
+ std::vector<memory_t> d_states, d_init_states, d_term_states;
+
+ void reset_metrics (u_char which);
+ void zero_metrics (u_char which);
+
+/*
+ * d_n_total_input_bits_per_stream: how many bits to store for each
+ * state to determine the best decoder-output (encoder-input) bits
+ */
+ size_t d_frame_size_bits;
+ size_t d_n_code_outputs, d_n_code_inputs, d_max_memory;
+ size_t d_time_count, d_n_total_input_bits_per_stream;
+ size_t d_n_saved_bits, d_n_saved_bits_start_ndx, d_n_traceback_els;
+ size_t d_n_states, d_n_input_combinations;
+ size_t d_states_ndx, d_up_term_ndx;
+ bool d_do_streaming, d_do_termination, d_do_mux_inputs;
+ char **d_save_buffer;
+ state_t_ptr d_states[2];
+ fsm_dec_t d_fsm;
+ size_t* d_up_term_states_ndx[2];
+ traceback_t_hdl d_out_buf;
+};
+
+#endif /* INCLUDED_DECODER_VITERBI_H */
Index: libecc/decoder_viterbi_block_full.cc
===================================================================
RCS file: libecc/decoder_viterbi_block_full.cc
diff -N libecc/decoder_viterbi_block_full.cc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libecc/decoder_viterbi_block_full.cc 5 Jul 2006 17:49:58 -0000
1.1
@@ -0,0 +1,1484 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_dec_blk_conv_soft_full.h>
+#include <gr_io_signature.h>
+#include <assert.h>
+#include <iostream>
+
+const int g_max_frame_size_bits = 10000000;
+const int g_max_num_streams = 10;
+const int g_num_bits_per_byte = 8;
+
+#define DO_TIME_THOUGHPUT 0
+#define DO_PRINT_DEBUG_INST 0
+#define DO_PRINT_DEBUG_INST_0 0
+#define DO_PRINT_DEBUG_INST_1 0
+#define DO_PRINT_DEBUG_INST_2 0
+#define DO_PRINT_DEBUG_FSM 0
+#define DO_PRINT_DEBUG_INIT 0
+#define DO_PRINT_DEBUG_UP 0
+#define DO_PRINT_DEBUG_UP_0 0
+#define DO_PRINT_DEBUG_UP_1 0
+#define DO_PRINT_DEBUG_MIDDLE 0
+#define DO_PRINT_DEBUG_MIDDLE_0 0
+#define DO_PRINT_DEBUG_MIDDLE_1 0
+#define DO_PRINT_DEBUG_TERM 0
+#define DO_PRINT_DEBUG_TERM_1 0
+#define DO_PRINT_DEBUG_OUTPUT 0
+#define DO_PRINT_DEBUG_OUTPUT_0 0
+#define DO_PRINT_DEBUG_EXIT 0
+#define DO_PRINT_DEBUG 0
+
+#if DO_TIME_THOUGHPUT
+#include <mld/mld_timer.h>
+#endif
+#if DO_PRINT_DEBUG
+#include <mld/n2bs.h>
+#endif
+
+gr_decoder_viterbi_block_soft_full_sptr
+gr_make_dec_blk_conv_soft_full
+(int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination)
+{
+ return gr_decoder_viterbi_block_soft_full_sptr
+ (new gr_decoder_viterbi_block_soft_full (frame_size_bits,
+ num_input_streams,
+ num_output_streams,
+ code_generator,
+ do_termination));
+}
+
+gr_decoder_viterbi_block_soft_full::gr_decoder_viterbi_block_soft_full
+(int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination)
+ : gr_block ("dec_blk_conv_soft_full",
+ gr_make_io_signature (0, 0, 0),
+ gr_make_io_signature (0, 0, 0))
+{
+// make sure the frame length makes sense, #1 - more later
+ if (frame_size_bits > g_max_frame_size_bits) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Requested frame length (" << frame_size_bits <<
+ " bits) must be at most " << g_max_frame_size_bits << " bits.\n";
+ assert (0);
+ }
+
+// check to make sure the number of input streams makes sense
+ if ((n_code_inputs <= 0) | (n_code_inputs > g_max_num_streams)) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Requested number of input streams (" <<
+ n_code_inputs << ") must be between 1 and " <<
+ g_max_num_streams << ".\n";
+ assert (0);
+ }
+
+// check to make sure the number of output streams makes sense
+ if ((n_code_outputs <= 0) | (n_code_outputs > g_max_num_streams)) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Requested number of output streams (" <<
+ n_code_outputs << ") must be between 1 and " <<
+ g_max_num_streams << ".\n";
+ assert (0);
+ }
+
+// make sure the code_generator is the correct length
+ if (code_generators.size () !=
+ ((size_t)(n_code_inputs * n_code_outputs))) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Number of code generator entries (" << code_generators.size () <<
+ ") is not equal to the product of the number of input and output" <<
+ " streams (" << (n_code_inputs * n_code_outputs) << ").\n";
+ assert (0);
+ }
+
+// create the class frame variables
+ d_frame_size_bits = frame_size_bits;
+ d_out_stream_el_size_bytes = out_stream_el_size_bytes;
+ d_n_code_inputs = n_code_inputs;
+ d_n_code_outputs = n_code_outputs;
+ d_do_streaming = (frame_size_bits == 0);
+ d_do_termination = (d_do_streaming == true) ? false : do_termination;
+ d_do_mux_inputs = do_mux_inputs;
+
+// allocate the vectors for doing the encoding. use 32-bit int's
+// actual bits to represent memory and the code, as it makes the
+// operations quite simple the state vectors.
+// code generates are for each I/O combination
+
+ d_code_generators.resize (d_n_code_inputs * d_n_code_outputs, 0);
+
+// check the input code_generator for correctness & find the memory order
+// t_max_mem will be the mamimum number of memories used by the generator
+// t_code_ndx is a counter over all input code_generator elements
+ int t_max_mem = 0, t_code_ndx = d_code_generators.size() - 1;
+// loop over all input streams first, output streams second
+ for (int n = d_n_code_outputs - 1; n >= 0; n--) {
+ int t_all_inputs_zero = 0;
+ for (int m = d_n_code_inputs - 1; m >= 0; m--) {
+ int t_in_code = code_generators[t_code_ndx];
+ t_all_inputs_zero |= t_in_code;
+ int t_code_mem = 0;
+// find the memory requirement for this code generator
+ while (t_in_code != 0) {
+ t_in_code >>= 1;
+ t_code_mem++;
+ }
+ if (t_code_mem > t_max_mem)
+ t_max_mem = t_code_mem;
+// store in d_code_generators in output-first ordering
+ d_code_generators[(m*d_n_code_outputs) + n] =
+ code_generators[t_code_ndx--];
+ }
+ if (t_all_inputs_zero == 0) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "At least 1 generator code for encode-output " << n+1 <<
+ " must be non-0.\n";
+ assert (0);
+ }
+ }
+
+// store the maximum memory order (e.g. "2" -> D^2)
+ d_max_memory = t_max_mem - 1;
+
+// make sure the frame length makes sense, #2
+ if (d_frame_size_bits < d_max_memory) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Requested frame length (" << d_frame_size_bits <<
+ " bit" << (d_frame_size_bits > 1 ? "s" : "") <<
+ ") must be at least 1 memory length (" << d_max_memory <<
+ " bit" << (d_max_memory > 1 ? "s" : "") <<
+ " for this code).\n";
+ assert (0);
+ }
+
+// NOTE: d_n_states is a 'u_long', and thus is quite limited in terms
+// of max memory and # of input streams to 2^32 states
+// This is OK, since that many states would be impossibly slow to decode!
+// might make this a "long long" (64 bits) in the future
+ d_n_states = 1 << (d_max_memory * d_n_code_inputs);
+ d_n_input_combinations = 1 << d_n_code_inputs;
+
+#if DO_PRINT_DEBUG_INST_0
+ std::cout << "Init:\n" <<
+ "d_frame_size_bits = " << d_frame_size_bits << "\n" <<
+ "d_out_stream_el_size_bytes = " << d_out_stream_el_size_bytes << "\n" <<
+ "d_n_code_inputs = " << d_n_code_inputs << "\n" <<
+ "d_n_code_outputs = " << d_n_code_outputs << "\n" <<
+ "d_do_streaming = " <<
+ ((d_do_streaming == true) ? "true" : "false") << "\n" <<
+ "d_do_termination = " <<
+ ((d_do_termination == true) ? "true" : "false") << "\n" <<
+ "d_do_mux_inputs = " <<
+ ((d_do_mux_inputs == true) ? "true" : "false") << "\n" <<
+ "d_max_memory = " << d_max_memory << "\n" <<
+ "d_n_states = " << d_n_states << "\n" <<
+ "d_n_input_combinations = " << d_n_input_combinations << "\n";
+#endif
+
+// leave the output multiple at 1 (element); will save any incomplete
+// output data (int's) in "d_save_buffer"; all input data will be consumed
+
+// create the correct input signature
+ int t_n_input_streams = ((d_do_mux_inputs == true) ?
+ 1 : n_code_outputs);
+
+ set_input_signature (gr_make_io_signature (t_n_input_streams,
+ t_n_input_streams,
+ sizeof (float)));
+// create the correct output signature
+ set_output_signature (gr_make_io_signature (n_code_inputs,
+ n_code_inputs,
+ d_out_stream_el_size_bytes));
+#if DO_PRINT_DEBUG_INST_0
+ std::cout <<
+ "input_signature = [" << t_n_input_streams << ", " <<
+ t_n_input_streams << ", " << sizeof (float) << "]\n" <<
+ "output_signature = [" << n_code_outputs << ", " <<
+ n_code_outputs << ", " << d_out_stream_el_size_bytes << "]\n";
+#endif
+
+// always start the fsm in the "init" state
+ d_fsm = fsm_dec_init;
+
+// create a vector of indexes to states when doing "up" or "termination";
+ d_up_term_states_ndx[0] = new size_t [d_n_states];
+ d_up_term_states_ndx[1] = new size_t [d_n_states];
+
+// create the traceback buffers
+// get the total number of out bits per stream
+ d_n_total_input_bits_per_stream = d_frame_size_bits;
+ if (d_do_termination == true)
+ d_n_total_input_bits_per_stream += d_max_memory;
+ d_n_traceback_els = d_n_total_input_bits_per_stream + 1;
+// create the output buffers:
+// this is a 2d matrix structure, where the first dimension
+// is the number of output bits; the second dimension is
+// the number of states.
+// When doing full frames (no tau), each bit-time's state's traceback
+// contains just the pointer to the previous bit-time's state's traceback
+// as well as the inputs for that connection.
+// No further work is required because each reverse-path is unique
+// once a given end-bit-time's state is determined to be "the one"
+ traceback_t_hdl t_out_buf =
+ d_out_buf = new traceback_t_ptr [d_n_traceback_els];
+ for (size_t n = d_n_traceback_els; n > 0; n--) {
+ (*t_out_buf++) = new traceback_t [d_n_states];
+ }
+
+ // create the save buffers
+ char** t_save_buffer = d_save_buffer = new char* [d_n_code_inputs];
+ size_t t_n_out_bytes = ((d_frame_size_bits / g_num_bits_per_byte) +
+ ((d_frame_size_bits % g_num_bits_per_byte) ? 1 : 0));
+ for (size_t n = 0; n < d_n_code_inputs; n++) {
+ (*t_save_buffer++) = new char [t_n_out_bytes];
+ }
+
+// reset the number of saved bits
+ d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
+
+// setup the internal structures for exiting and entering states
+
+#if DO_PRINT_DEBUG_INST_0
+ std::cout <<
+ "d_n_total in bits / stream = " << d_n_total_input_bits_per_stream << "\n"
<<
+ "d_n_traceback_els = " << d_n_traceback_els << "\n" <<
+ "t_n_out_bytes / stream = " << t_n_out_bytes << "\n";
+#endif
+
+// Find the approximate output rate / input rate
+// each input item produces 1 bit of an output item w/o termination
+ double t_rel_rate = (double)(d_out_stream_el_size_bytes *
g_num_bits_per_byte);
+ if (d_do_termination == true) {
+// include termination bits
+ t_rel_rate *= (((double) d_frame_size_bits) /
+ ((double) d_n_total_input_bits_per_stream));
+ }
+// Set the approximate output rate / input rate
+ set_relative_rate (t_rel_rate);
+
+// 'new' everything first; no connections yet
+ state_t_ptr t_state = d_states[0] = new state_t [d_n_states];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections
+ = new connection_t [d_n_input_combinations];
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ t_connection->d_output_bits = new float [d_n_code_outputs];
+ }
+ }
+
+// 'new' everything first; no connections yet
+ t_state = d_states[1] = new state_t [d_n_states];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections
+ = new connection_t [d_n_input_combinations];
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ t_connection->d_output_bits = new float [d_n_code_outputs];
+ }
+ }
+
+// temporary memory and mask for output bit computations
+ size_t t_memory[d_n_code_inputs];
+ size_t t_memory_mask = ((2 << d_max_memory) - 1) ^ 1;
+
+#if DO_PRINT_DEBUG
+ size_t t_state_print_bits = (d_max_memory * d_n_code_inputs) + 1;
+ size_t t_mem_print_bits = d_max_memory + 2;
+
+ std::cout << "Setting States and Connections\n";
+#endif
+
+// loop over all possible memory states
+ state_t_ptr t_state0 = d_states[0];
+ state_t_ptr t_state1 = d_states[1];
+ for (size_t n = 0; n < d_n_states; n++, t_state0++, t_state1++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "Starting state # " << n << " == " <<
+ n2bs (n, t_state_print_bits) << "\n";
+#endif
+// retrieve the memory values for this state
+// probably a faster way to do this, but since this is
+// executed only upon instantiation, whatever.
+ size_t* t_mem_ptr = t_memory;
+ for (size_t p = 0; p < d_n_code_inputs; p++) {
+ int t_mem = state_get_from (n, p, d_max_memory);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "s_g_f (" <<
+ n2bs (n, t_state_print_bits) << ", " <<
+ p << ", " << d_max_memory << ") => t_m = " <<
+ n2bs (t_mem, t_mem_print_bits) << "\n";
+#endif
+// shift them by 1 (and mask) to make updating for all inputs simple
+ (*t_mem_ptr++) = t_mem << 1;
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "t_m_p[" << p << "] = " <<
+ n2bs (t_mem << 1, t_mem_print_bits) << " == (" <<
+ n2bs (t_mem, t_mem_print_bits) << " << 1)\n";
+#endif
+ }
+
+// loop over all possible input values, 1 bit per input stream
+ connection_t_ptr t_connection0 = t_state0->d_connections;
+ connection_t_ptr t_connection1 = t_state1->d_connections;
+ for (size_t q = 0; q < d_n_input_combinations;
+ q++, t_connection0++, t_connection1++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "Starting inputs " << q << " == " <<
+ n2bs (q, d_n_code_inputs + 1) << "\n";
+#endif
+
+// update memory for this set of inputs
+ t_mem_ptr = t_memory;
+ size_t t_this_input = q;
+
+// loop over all code inputs, and update just the single input bit
+ for (size_t r = d_n_code_inputs; r > 0; r--) {
+ int t_mem = (*t_mem_ptr) & t_memory_mask;
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "t_m = " << n2bs (t_mem, t_mem_print_bits) <<
+ " == " << n2bs (*t_mem_ptr, t_mem_print_bits) <<
+ " & " << n2bs (t_memory_mask, t_mem_print_bits) << "\n";
+#endif
+ (*t_mem_ptr++) = t_mem | (t_this_input & 1);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "t_m_p[" << (d_n_code_inputs - r) << "] = " <<
+ n2bs (t_mem | (t_this_input & 1), t_mem_print_bits) <<
+ " == t_m | " << (t_this_input & 1) << "\n";
+#endif
+ t_this_input >>= 1;
+ }
+
+// got the updated memory for this particular state & inputs
+// recreate the "to" state from the updated memory
+ t_mem_ptr = t_memory;
+ size_t t_out_state = 0;
+ for (size_t p = 0; p < d_n_code_inputs; p++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "s_a_t (" <<
+ n2bs (t_out_state, t_state_print_bits) <<
+ ", " << n2bs (*t_mem_ptr, t_mem_print_bits) << ", " << p <<
+ ", " << d_max_memory << ") ==> t_o_s out = ";
+#endif
+ state_add_to (t_out_state, *t_mem_ptr++, p, d_max_memory);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << n2bs (t_out_state, t_state_print_bits) << "\n";
+#endif
+ }
+
+// get the "to" state pointers from d_states[0] to [1]
+ state_t_ptr t_to_state = &(d_states[1][t_out_state]);
+ t_connection0->d_to = t_to_state;
+ t_connection0->d_to_ndx = t_out_state;
+ float* t_output_bit0 = t_connection0->d_output_bits;
+
+// get the "to" state pointers from d_states[1] to [0]
+ t_to_state = &(d_states[0][t_out_state]);
+ t_connection1->d_to = t_to_state;
+ t_connection1->d_to_ndx = t_out_state;
+ float* t_output_bit1 = t_connection1->d_output_bits;
+
+// determine the ideal output values: loop over all outputs
+ size_t t_vec_ctr = 0;
+ for (size_t s = 0; s < d_n_code_outputs; s++) {
+
+// loop over all inputs, xor'ing the result each time
+ int t_out_result = 0;
+ t_mem_ptr = t_memory;
+ for (size_t t = 0; t < d_n_code_inputs; t++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "b_i = " << n2bs (t_out_result, t_mem_print_bits) <<
+ ", st[" << t << "] = " << n2bs ((*t_mem_ptr), t_mem_print_bits) <<
+ ", cg[" << t_vec_ctr << "] = " <<
+ n2bs (d_code_generators[t_vec_ctr], t_mem_print_bits) <<
+ ", st[] & cg[] = " << n2bs ((*t_mem_ptr) &
+ d_code_generators[t_vec_ctr],
+ t_mem_print_bits);
+#endif
+ t_out_result ^= ((*t_mem_ptr++) &
+ d_code_generators[t_vec_ctr++]);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << ", b_o = " <<
+ n2bs (t_out_result, t_mem_print_bits) << '\n';
+#endif
+ }
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "b_r = " << n2bs (t_out_result, t_mem_print_bits);
+#endif
+// sum the number of set bits, mod 2, for the output bit
+ size_t t_out_bit = t_out_result & 1;
+ for (size_t v = d_max_memory; v > 0; v--) {
+ t_out_result >>= 1;
+ t_out_bit ^= (t_out_result & 1);
+ }
+
+// store the result for this particular output stream,
+// converting the bit 1 -> +1.0, and 0 -> -1.0
+ float t_out_value = (float)(((int)(t_out_bit << 1)) - 1);
+ *t_output_bit0++ = t_out_value;
+ *t_output_bit1++ = t_out_value;
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << ", o_v = " << t_out_value << "\n";
+#endif
+
+// finished (for) all output values
+ }
+// finished (for) over all possible input values
+ }
+// finished (for) over all possible states
+ }
+
+// so now d_states is/are completely populated!
+// These make for simple access to looping over all possible inputs or
+// outputs for a given state to determine what the path with the best
+// metric is.
+
+#if DO_PRINT_DEBUG_INST_2
+// loop over all possible memory states
+ std::cout << "State Tables\n";
+ t_state0 = d_states[0];
+ t_state1 = d_states[1];
+ for (size_t n = 0; n < d_n_states; n++, t_state0++, t_state1++) {
+ std::cout << "d_s[0][" << n << "] = " << t_state0 << "\n";
+// loop over all possible input values, 1 bit per input stream
+ connection_t_ptr t_connection0 = t_state0->d_connections;
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection0++) {
+ std::cout << "s0[" << n2bs (n, t_state_print_bits) << "][" <<
+ n2bs (q, d_n_code_inputs+1) << "] = " << t_connection0 <<
+ " -> s1[" << n2bs (t_connection0->d_to_ndx, t_state_print_bits) <<
+ "] = " << t_connection0->d_to << "\n";
+ }
+ std::cout << "d_s[1][" << n << "] = " << t_state1 << "\n";
+ connection_t_ptr t_connection1 = t_state1->d_connections;
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection1++) {
+ std::cout << "s1[" << n2bs (n, t_state_print_bits) << "][" <<
+ n2bs (q, d_n_code_inputs+1) << "] = " << t_connection1 <<
+ " -> s0[" << n2bs (t_connection1->d_to_ndx, t_state_print_bits) <<
+ "] = " << t_connection1->d_to << "\n";
+ }
+ }
+
+ traceback_t_hdl t_out_bufs = d_out_buf;
+ for (size_t n = 0; n < d_n_traceback_els; n++, *t_out_bufs++) {
+ traceback_t_ptr t_out_buf = *t_out_bufs;
+ for (size_t m = 0; m < d_n_states; m++, t_out_buf++) {
+ std::cout << "tb[" << n << "] = " << t_out_bufs <<
+ ", &tb[" << n << "][" << m << "] = " << (&d_out_buf[n][m]) <<
+ ", tb[" << n << "," << m << "] = " << t_out_buf << "\n";
+ }
+ }
+
+ std::cout << "Done with instantiation.\n";
+#endif
+}
+
+gr_decoder_viterbi_block_soft_full::~gr_decoder_viterbi_block_soft_full
+()
+{
+// reverse over from allocation
+
+ delete [] d_up_term_states_ndx[0];
+ delete [] d_up_term_states_ndx[1];
+
+// delete the state's structures
+ state_t_ptr t_state = d_states[0];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections;
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ delete [] t_connection->d_output_bits;
+ }
+ delete [] t_state->d_connections;
+ }
+ delete [] d_states[0];
+
+ t_state = d_states[1];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections;
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ delete [] t_connection->d_output_bits;
+ }
+ delete [] t_state->d_connections;
+ }
+ delete [] d_states[1];
+
+// delete the save buffer
+ char** t_save_buffer = d_save_buffer;
+ for (size_t n = 0; n < d_n_code_inputs; n++) {
+ delete [] (*t_save_buffer++);
+ }
+ delete [] d_save_buffer;
+
+// delete the output buffer
+ traceback_t_hdl t_out_buf = d_out_buf;
+ for (size_t n = d_n_traceback_els; n > 0; n--) {
+ delete [] (*t_out_buf++);
+ }
+ delete [] d_out_buf;
+}
+
+void gr_decoder_viterbi_block_soft_full::reset_metrics (u_char which)
+{
+ state_t_ptr t_state = d_states[which&1];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ t_state->d_max_metric = -1e10;
+#if 0
+// probably don't need to do these, try removing them later
+ t_state->d_max_state_ndx = 0;
+ t_state->d_max_input = -1;
+#endif
+ }
+}
+
+void gr_decoder_viterbi_block_soft_full::zero_metrics (u_char which)
+{
+ state_t_ptr t_state = d_states[which&1];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ t_state->d_max_metric = 0;
+#if 0
+// probably don't need to do these, try removing them later
+ t_state->d_max_state_ndx = -1;
+ t_state->d_max_input = -1;
+#endif
+ }
+}
+
+void gr_decoder_viterbi_block_soft_full::forecast
+(int noutput_items,
+ gr_vector_int &ninput_items_required)
+{
+ int ninput_items = fixed_rate_noutput_to_ninput (noutput_items);
+
+ int ninputs = ninput_items_required.size();
+ for (int n = 0; n < ninputs; n++)
+ ninput_items_required[n] = ninput_items;
+}
+
+/*
+ * Compute the number of input items (soft symbols [floats]) needed to produce
+ * 'noutput' items (elements). For convolutional decoders, there is 1
+ * bit output per bit input per stream, with the addition of a some
+ * bits for trellis termination if selected. Without termination,
+ * there is exactly 1:1 input to output (1 symbol in to 1 bit out),
+ * no matter the encoding type.
+ *
+ * if (not terminating), then get the number of output bytes.
+ *
+ * otherwise, find the number of frames (not necessarily and integer),
+ * and then compute the number of input bits (including termination)
+ * required to produce those frames. Subtract the number of bits
+ * leftover from the previous computation, then find the number of input
+ * elements (soft symbols), ceil'd to make sure there are enough.
+ *
+ * finally, if the input streams are mux'ed, then multiply by the
+ * number of inputs.
+ */
+
+int
+gr_decoder_viterbi_block_soft_full::fixed_rate_noutput_to_ninput
+(int noutput_items)
+{
+ int t_ninput_items = 0;
+ int t_noutput_bits = (noutput_items * d_out_stream_el_size_bytes *
+ g_num_bits_per_byte) - d_n_saved_bits;
+// if there are enough saved bits, just use those, no inputs required
+ if (t_noutput_bits <= 0)
+ return (t_ninput_items);
+
+// remove any bits already in the decoding trellis
+ if (d_time_count != 0) {
+ int t_time_bits = ((d_time_count > d_frame_size_bits) ? 0 :
+ d_frame_size_bits - d_time_count);
+ t_noutput_bits -= t_time_bits;
+ t_ninput_items += t_time_bits;
+ }
+// if completing this trellis doesn't create enough outputs ...
+ if (t_noutput_bits > 0) {
+
+// there is a 1:1 ratio between input symbols and output bits (per
+// stream), except for termination bits which are already taken into
+// account in the total # of input bits per stream class variable;
+// need to round the # output bits to the
+
+// find the number of frames, ceil'd to the next higher integer
+ int t_nframes = (int) ceilf (((float) t_noutput_bits) /
+ ((float) d_frame_size_bits));
+// find the number of required input bits
+ t_ninput_items += t_nframes * d_n_total_input_bits_per_stream;
+ }
+
+// if doing mux'ing, there are more elements in the single input
+ if (d_do_mux_inputs == true) {
+ t_ninput_items *= d_n_code_outputs;
+ }
+ return (t_ninput_items);
+}
+
+int
+gr_decoder_viterbi_block_soft_full::general_work
+(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+#if DO_TIME_THOUGHPUT
+ struct timeval t_tp;
+ start_timer (&t_tp);
+#endif
+#if DO_PRINT_DEBUG
+ size_t t_state_print_bits = (d_max_memory * d_n_code_inputs) + 1;
+ size_t t_mem_print_bits = d_max_memory + 2;
+#endif
+// setup variables for quicker access
+ const float **in_buf = (const float **) &input_items[0];
+ char **out_buf = (char **) &output_items[0];
+ int t_in_buf_ndx = 0, t_out_buf_ndx = 0;
+ int t_out_bit_shift = 0;
+ int t_ninput_items = fixed_rate_noutput_to_ninput (noutput_items);
+ int t_noutput_bytes = noutput_items * d_out_stream_el_size_bytes;
+
+#if DO_PRINT_DEBUG_INST
+ std::cout << "# output items = " << noutput_items << " (" <<
+ t_noutput_bytes << " Bytes, " << (t_noutput_bytes * g_num_bits_per_byte) <<
+ " bits), # input items = " << t_ninput_items << " Symbols\n";
+ for (size_t n = 0; n < ninput_items.size(); n++) {
+ std::cout << "# input items [" << n << "] = " << ninput_items[n] << "\n";
+ }
+#endif
+
+// put any leftover bits into the output
+ if (d_n_saved_bits != 0) {
+// copy the leftover from the save buffer
+// check to make sure it will all fit
+ size_t t_noutput_bits = t_noutput_bytes * g_num_bits_per_byte;
+ size_t t_n_copy;
+ if (t_noutput_bits < d_n_saved_bits) {
+// asking for fewer bits than available; set to copy
+// just what's being asked for
+ t_n_copy = t_noutput_bytes;
+ } else {
+// asking for at least as many bits as available; set to copy all
+ t_out_buf_ndx = d_n_saved_bits / g_num_bits_per_byte;
+ t_out_bit_shift = d_n_saved_bits % g_num_bits_per_byte;
+ t_n_copy = t_out_buf_ndx + (t_out_bit_shift != 0 ? 1 : 0);
+ }
+// do the copy for all output streams (code inputs)
+// copy starting at save buffer index "start"
+ for (size_t n = 0; n < d_n_code_inputs; n++)
+ bcopy (&(d_save_buffer[n][d_n_saved_bits_start_ndx]),
+ out_buf[n], t_n_copy);
+#if DO_PRINT_DEBUG_INST
+ std::cout << "Copied " << t_n_copy << " Byte" <<
+ (t_n_copy != 1 ? "s" : "") << ": s_b[][" <<
+ d_n_saved_bits_start_ndx << "] => o_b[][0]\n" <<
+ "# saved bits = " << d_n_saved_bits <<
+ ", o_b_ndx = " << t_out_buf_ndx <<
+ ", bit shift = " << t_out_bit_shift << "\n";
+#endif
+// update the number of saved bits and start
+ if (t_noutput_bits < d_n_saved_bits) {
+// asking for fewer bit than available: update
+// the number of saved bits and their starting index
+ d_n_saved_bits_start_ndx += t_noutput_bytes;
+ d_n_saved_bits -= (t_noutput_bytes * g_num_bits_per_byte);
+#if DO_PRINT_DEBUG_INST
+ std::cout << "Updated # saved bits = " << d_n_saved_bits <<
+ ", index = " << d_n_saved_bits_start_ndx << "\n";
+#endif
+// nothing to consume; return the desired number of output items
+ return (noutput_items);
+ } else {
+ d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
+ }
+ }
+#if DO_PRINT_DEBUG_INST
+ std::cout << "Starting FSM in state: " <<
+ (d_fsm == fsm_dec_init ? "init" :
+ (d_fsm == fsm_dec_doing_up ? "up" :
+ (d_fsm == fsm_dec_doing_middle ? "middle" :
+ (d_fsm == fsm_dec_doing_term ? "term" :
+ (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "\n";
+#endif
+
+// while there are input items to create
+ while (t_out_buf_ndx < t_noutput_bytes) {
+#if DO_PRINT_DEBUG_FMS
+ std::cout << "Starting 'while': processing " << t_in_buf_ndx << " of " <<
+ t_ninput_items << " items.\nJumping to state '" <<
+ (d_fsm == fsm_dec_init ? "init" :
+ (d_fsm == fsm_dec_doing_up ? "up" :
+ (d_fsm == fsm_dec_doing_middle ? "middle" :
+ (d_fsm == fsm_dec_doing_term ? "term" :
+ (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "'\n";
+#endif
+// jump to the correct state in the fsm
+ switch (d_fsm) {
+ case fsm_dec_doing_up:
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Starting fsm_dec_doing_up\n";
+#endif
+// set the number of up_down indices
+ size_t t_n_up_down_ndx = 1 << (d_n_code_inputs *
+ d_time_count);
+// stay in this state until the correct number of input symbols are
+// reached; exit also if we run out of input symbols to process
+ while ((d_time_count < d_max_memory) &
+ (t_in_buf_ndx < t_ninput_items)) {
+#if DO_PRINT_DEBUG_UP_0
+ std::cout << "Doing 'while' loop:\n" <<
+ "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" <<
+ "d_time_count = " << d_time_count << "\n" <<
+ "d_max_memory = " << d_max_memory << "\n" <<
+ "t_in_buf_ndx = " << t_in_buf_ndx << "\n" <<
+ "t_ninput_items = " << t_ninput_items << "\n";
+#endif
+// use the "from" states, loop over all inputs and compute the metric for
+// each & store it in the "to" state at the end of the connection.
+// no need to compare metrics yet, since none join into any given state
+
+#if 0
+// reset the "to" state's metrics
+// probably don't need to do this; try removing later
+ reset_metrics (d_states_ndx ^ 1);
+#if DO_PRINT_DEBUG_UP
+ std::cout << "Reset Metrics\n";
+#endif
+#endif
+
+// reset the state's index for each set of new inputs
+ size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+ size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
+// loop over all current stored "up" states
+ for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+ size_t t_state_ndx = *t_state_ndx_ptr++;
+// get a pointer to this state's structure
+ state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// get the connections for all inputs
+ connection_t_ptr t_connection = t_state->d_connections;
+#if DO_PRINT_DEBUG_UP_0
+ std::cout << "Looping over all 'up' states:\n" <<
+ "n = " << n << "\n" <<
+ "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" <<
+ "d_states_ndx = " << d_states_ndx << "\n" <<
+ "t_state_ndx = " << t_state_ndx << "\n" <<
+ "d_n_input_combs = " << d_n_input_combinations << "\n" <<
+ "t_state = " << t_state << "\n" <<
+ "t_connection = " << t_connection << "\n";
+#endif
+// loop over all possible input values, 1 bit per input stream
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
+// find the "to" state for this connection
+ state_t_ptr t_to_state = t_connection->d_to;
+// get the output bits for this connection
+ float* t_output_bit = t_connection->d_output_bits;
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+#if DO_PRINT_DEBUG_UP_0
+ std::cout <<
+ "to state index = " << t_connection->d_to_ndx << "\n" <<
+ "current metric = " << t_metric << "\n";
+#endif
+ if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+ const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+ for (size_t r = d_n_code_outputs; r > 0; r--) {
+#if DO_PRINT_DEBUG_UP
+ std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
+ *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += ((*t_in_buf++) * (*t_output_bit++));
+#if DO_PRINT_DEBUG_UP
+ std::cout << t_metric << "\n";
+#endif
+ }
+ } else {
+// loop over all encoder-output values
+ for (size_t r = 0; r < d_n_code_outputs; r++) {
+#if DO_PRINT_DEBUG_UP
+ std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
+ ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+#if DO_PRINT_DEBUG_UP
+ std::cout << t_metric << "\n";
+#endif
+ }
+ }
+// get the "to" state index
+ size_t t_to_ndx = t_connection->d_to_ndx;
+// store the metric in the "to" state; should not have been used before
+ t_to_state->d_max_metric = t_metric;
+// add the "to" state index to the "up" state list
+ *t_next_state_ndx_ptr++ = t_to_ndx;
+// update the traceback structure, depending on which variety it is
+// doing full trellis before decoding; use d_out_buf
+// simple: get the current state & output state
+ traceback_t_ptr t_out_buf = &(d_out_buf[d_time_count]
+ [t_state_ndx]);
+ traceback_t_ptr t_next_out_buf = &(d_out_buf[d_time_count+1]
+ [t_to_ndx]);
+#if DO_PRINT_DEBUG_UP_1
+ std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n" <<
+ "ndx[" << n << "] == " << t_state_ndx <<
+ ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+ "]: max_ndx = " <<
+ n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+ ", input = " << n2bs(q, d_n_code_inputs+1) <<
+ ": " << t_next_out_buf << " => " << t_out_buf << "\n";
+#endif
+// and connect output to the current, set inputs on output
+ t_next_out_buf->d_prev = t_out_buf;
+ t_next_out_buf->d_inputs = q;
+// finished (for) this input value
+ }
+// finished (for) this "up_term" state
+ }
+// increment the in_buf index, depending on mux'ing or not
+ t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counter
+ d_time_count++;
+// update the number of "up_term" states
+ d_up_term_ndx ^= 1;
+// increase the number of using states
+ t_n_up_down_ndx <<= d_n_code_inputs;
+// change which d_states' index to use as starting
+ d_states_ndx ^= 1;
+// finished (while) staying in this fsm state or not
+ }
+// if reached the end of doing the "up" part of the trellis,
+// switch states into the middle
+ if (d_time_count == d_max_memory) {
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Setting FSM to fsm_dec_doing_middle\n";
+#endif
+ d_fsm = fsm_dec_doing_middle;
+ }
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_doing_up\n";
+#endif
+ break;
+ case (fsm_dec_doing_middle):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_doing_middle\n";
+#endif
+// stay in this state until the correct number of input symbols is
+// reached (if doing block coding), or until there are no more input
+// symbols to parse
+ while (((d_frame_size_bits != 0) &
+ (d_time_count < d_frame_size_bits) &
+ (t_in_buf_ndx < t_ninput_items)) |
+ ((d_frame_size_bits == 0) &
+ (t_in_buf_ndx < t_ninput_items))) {
+// use all states, loop over all inputs, compute the metric for
+// each; compare the current metric with all previous stored metric in the
+// endpoint of the connection to find the highest one.
+
+// reset the "to" state's metrics
+ reset_metrics (d_states_ndx ^ 1);
+// get the state's index for each set of new inputs
+ state_t_ptr t_state = d_states[d_states_ndx];
+#if DO_PRINT_DEBUG_MIDDLE
+ std::cout << "Time Count " << (d_time_count+1) << " of " <<
+ d_frame_size_bits << "\n" <<
+ "d_states_ndx = " << d_states_ndx << "\n";;
+#endif
+// loop over all current states
+ for (size_t n = 0; n < d_n_states; n++, t_state++) {
+// loop over all possible input values, 1 bit per input stream
+ connection_t_ptr t_connection = t_state->d_connections;
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "Looping over all 'middle' states: " <<
+ n << " of " << d_n_states << "\n";
+#endif
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "Input = " << n2bs(q, d_n_code_inputs+1) << "\n";
+#endif
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+// get the "to" state
+ state_t_ptr t_to_state = t_connection->d_to;
+// get that state's metric
+ float t_to_metric = t_to_state->d_max_metric;
+// see if the computation is even needed;
+// maximum change is d_n_code_outputs if all bits match exactly
+ if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "!not computing metric!\n";
+#endif
+ continue;
+ }
+// metrics are close enough; do the computation and the compare
+// get the output bits for this connection
+ float* t_output_bit = t_connection->d_output_bits;
+ if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+ const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+ for (size_t r = d_n_code_outputs; r > 0; r--) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
+ *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += ((*t_in_buf++) * (*t_output_bit++));
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << t_metric << "\n";
+#endif
+ }
+ } else {
+// loop over all encoder-output values
+ for (size_t r = 0; r < d_n_code_outputs; r++) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
+ ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << t_metric << "\n";
+#endif
+ }
+ }
+// done with this input value; compare old and new metrics
+ if (t_metric > t_to_metric) {
+#if DO_PRINT_DEBUG_MIDDLE
+ std::cout << "New Metric to s[" <<
+ n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
+ if (t_to_state->d_max_metric == -1e10) {
+ std::cout << "setting to ";
+ } else {
+ std::cout << "was s[" <<
+ n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
+ "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
+ "]@ " << t_to_state->d_max_metric << " now ";
+ }
+ std::cout << "s[" << n2bs(n,t_state_print_bits) << "] i[" <<
+ n2bs (q, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
+#endif
+// new metric is better; copy that info into the "to" state
+ t_to_state->d_max_metric = t_metric;
+ t_to_state->d_max_state_ndx = n;
+ t_to_state->d_max_input = q;
+ }
+// finished (for) this input value
+ }
+// finished (for) this state
+ }
+// done with all states and all inputs; now update the traceback structure
+// change which d_states' index to use as starting
+ d_states_ndx ^= 1;
+// get the state's index for the "to" set of new inputs to get the
+// "max" stuff from
+ t_state = d_states[d_states_ndx];
+// update the traceback structure
+// loop over all current states
+ traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
+ traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
+#if DO_PRINT_DEBUG_MIDDLE_1
+ std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
+#endif
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+// simple: get the current state & output state
+// and connect output to the current, set inputs on output
+ traceback_t_ptr t_out_buf = t_out_bufs++;
+ traceback_t_ptr t_prev_out_buf =
+ &(t_prev_out_bufs[t_state->d_max_state_ndx]);
+#if DO_PRINT_DEBUG_MIDDLE_1
+ std::cout << "s[" << n2bs(d_n_states-n,t_state_print_bits) <<
+ "]: max_ndx = " <<
+ n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+ ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
+ ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
+#endif
+ t_out_buf->d_prev = t_prev_out_buf;
+ t_out_buf->d_inputs = t_state->d_max_input;
+// finished doing this state
+ }
+// increment the in_buf index, depending on mux'ing or not
+ t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counter
+ d_time_count++;
+// finished (while) staying in this fsm state or not
+ }
+ if ((d_frame_size_bits != 0) &
+ (d_time_count == d_frame_size_bits)) {
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Setting FSM to fsm_dec_doing_term\n";
+#endif
+ d_fsm = fsm_dec_doing_term;
+ }
+ break;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_doing_middle\n";
+#endif
+ case (fsm_dec_doing_term):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_doing_term\n";
+#endif
+// set the "next" up_down index to the end of their states
+ size_t t_time_count = d_max_memory - (d_time_count - d_frame_size_bits);
+ t_n_up_down_ndx = 1 << (d_n_code_inputs * t_time_count);
+// stay in this state until the correct number of input symbols are
+// reached; exit also if we run out of input symbols to process
+ while ((t_time_count > 0) &
+ (t_in_buf_ndx < t_ninput_items)) {
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "Doing time " << (d_max_memory - t_time_count + 1) <<
+ " of " << d_max_memory << "; starting buf[" << t_in_buf_ndx <<
+ "] of [" << t_ninput_items << "]\n";
+#endif
+// use the "to" states,
+// FIXME: loop over just the "0" inputs
+// and compute the metric for
+// each, compare & store it in the "to" state at the end of the connection.
+
+// reset the "to" state's metrics
+ reset_metrics (d_states_ndx ^ 1);
+// reset the state's index for each set of new inputs
+ size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+ size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
+// loop over all current stored "term" state indeces
+ for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+ size_t t_state_ndx = *t_state_ndx_ptr++;
+ state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// loop over just the all 0 input value (d_connections[0])
+ connection_t_ptr t_connection = t_state->d_connections;
+// get the "to" state
+ state_t_ptr t_to_state = t_connection->d_to;
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+// get that state's metric
+ float t_to_metric = t_to_state->d_max_metric;
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "Term state " << (n+1) << " of " << t_n_up_down_ndx <<
+ "; using d_s[" << d_states_ndx << "][" <<
+ n2bs(t_state_ndx,t_state_print_bits) << "]\n";
+#endif
+// see if the computation is even needed;
+// maximum change is d_n_code_outputs if all bits match exactly
+ if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "!not computing metric!\n";
+#endif
+ continue;
+ }
+// metrics are close enough; do the computation and the compare
+// get the output bits for this connection
+ float* t_output_bit = t_connection->d_output_bits;
+ if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+ const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+ for (size_t r = d_n_code_outputs; r > 0; r--) {
+ t_metric += ((*t_in_buf++) * (*t_output_bit++));
+ }
+ } else {
+// loop over all encoder-output values
+ for (size_t r = 0; r < d_n_code_outputs; r++) {
+ t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+ }
+ }
+// done with this input value; compare old and new metrics
+// see if it's the best metric
+ if (t_metric > t_to_metric) {
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "New Metric to s[" <<
+ n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
+ if (t_to_state->d_max_metric == -1e10) {
+ std::cout << "setting to ";
+ } else {
+ std::cout << "was s[" <<
+ n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
+ "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
+ "]@ " << t_to_state->d_max_metric << " now ";
+ }
+ std::cout << "s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+ "] i[" << n2bs (0, d_n_code_inputs+1) << "]@ " << t_metric <<
"\n";
+#endif
+ t_to_state->d_max_metric = t_metric;
+ t_to_state->d_max_state_ndx = t_state_ndx;
+ t_to_state->d_max_input = 0;
+ }
+// add the "to" state's index to the "next" set of state's indices list
+ *t_next_state_ndx_ptr++ = t_connection->d_to_ndx;
+// finished (for) this state
+ }
+// done with all states and all inputs; now update the traceback structure
+// change which d_states' index to use as starting
+ d_states_ndx ^= 1;
+// update the number of "up_term" states
+ d_up_term_ndx ^= 1;
+// reduce the number of using states
+ t_n_up_down_ndx >>= d_n_code_inputs;
+// reset the state's index for each set of new inputs
+ t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+// update the traceback structure
+// loop over all current states
+ traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
+ traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
+#if DO_PRINT_DEBUG_TERM_1
+ std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
+#endif
+// loop over all current stored "term" state indices
+ for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+// get the start index and then pointer to each of the "to" states,
+// which hold the newest "max" stuff
+ size_t t_state_ndx = *t_state_ndx_ptr++;
+ state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// simple: get the current state & output state
+// and connect output to the current, set inputs on output
+ traceback_t_ptr t_out_buf = &(t_out_bufs[t_state_ndx]);
+ traceback_t_ptr t_prev_out_buf =
+ &(t_prev_out_bufs[t_state->d_max_state_ndx]);
+#if DO_PRINT_DEBUG_TERM_1
+ std::cout << "ndx[" << n << "] == " << t_state_ndx <<
+ ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+ "]: max_ndx = " <<
+ n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+ ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
+ ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
+#endif
+ t_out_buf->d_prev = t_prev_out_buf;
+ t_out_buf->d_inputs = t_state->d_max_input;
+// finished (for) this state
+ }
+// increment the in_buf index, depending on mux'ing or not
+ t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counters
+ t_time_count--;
+ d_time_count++;
+// finished (while) staying in this fsm state or not
+ }
+ if (t_time_count == 0) {
+// finished this trellis, now move as much of the decoded input to the
+// output buffer as possible
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Setting FSM to fsm_dec_output\n";
+#endif
+ d_fsm = fsm_dec_output;
+ }
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_doing_term\n";
+#endif
+ break;
+ case (fsm_dec_output):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_output.\n";
+#endif
+// this is done in reverse bit order (last time to first time)
+// using the traceback structure in d_out_buf, starting with
+// the maximum valued one in the last time slot, then using
+// the traceback's "d_prev" link to trace the trellis back
+
+// see where the output data will terminate
+ int t_next_out_buf_ndx = (t_out_buf_ndx +
+ (d_frame_size_bits / g_num_bits_per_byte));
+ int t_next_out_bit_shift = (t_out_bit_shift +
+ (d_frame_size_bits % g_num_bits_per_byte));
+ if (t_next_out_bit_shift >= g_num_bits_per_byte) {
+ t_next_out_bit_shift -= g_num_bits_per_byte;
+ t_next_out_buf_ndx++;
+ }
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "First bit in at out[][" << t_out_buf_ndx << "].[" <<
+ t_out_bit_shift << "] -> " << d_frame_size_bits << " bits == " <<
+ (d_frame_size_bits / g_num_bits_per_byte) << " Byte" <<
+ ((d_frame_size_bits / g_num_bits_per_byte) != 1 ? "s" : "") <<
+ " + " << (d_frame_size_bits % g_num_bits_per_byte) << " bit" <<
+ ((d_frame_size_bits % g_num_bits_per_byte) != 1 ? "s" : "") <<
+ "\nNext set of bits start at out[][" << t_next_out_buf_ndx <<
+ "].[" << t_next_out_bit_shift << "]\n";
+#endif
+// find the starting traceback structure
+ traceback_t_ptr t_out_buf;
+ if (d_do_termination == true) {
+// FIXME: assume termination state == 0
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Using termination; going through trellis for " <<
+ d_max_memory << " bit" <<
+ ((d_max_memory != 1) ? "s" : "") << "\n";
+#endif
+ t_out_buf = &(d_out_buf[d_time_count][0]);
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Starting traceback ptr " << t_out_buf << "\n";
+#endif
+// skip over the termination bits
+ for (size_t n = d_max_memory; n > 0; n--) {
+ t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+ }
+ } else {
+// no termination but doing block coding;
+// FIXME: use the state with the bext metric
+// get the state's index for each set of new inputs
+ state_t_ptr t_state = d_states[d_states_ndx];
+ float t_max_metric = t_state->d_max_metric;
+ size_t t_max_state_ndx = 0;
+ t_state++;
+// loop over all current states
+ for (size_t n = 1; n < d_n_states; n++, t_state++) {
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+// compare with current max
+ if (t_metric > t_max_metric) {
+ t_max_metric = t_metric;
+ t_max_state_ndx = n;
+ }
+ }
+// get the correct out_buf reference to start with
+ t_out_buf = &(d_out_buf[d_time_count][t_max_state_ndx]);
+ }
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "Found starting traceback ptr " << t_out_buf <<
+ "; getting all " << d_frame_size_bits << " bits per stream.\n";
+#endif
+// now we've got the starting traceback structure address;
+// check to make sure there is enough space in each output buffer
+ size_t t_frame_bit_ndx = d_frame_size_bits;
+ if ((t_next_out_buf_ndx > t_noutput_bytes) |
+ ((t_next_out_buf_ndx == t_noutput_bytes) &
+ (t_next_out_bit_shift != 0))) {
+// not enough space for all output bits;
+// find the number of extra bits to save
+ size_t t_save_buf_ndx = t_next_out_buf_ndx - t_noutput_bytes;
+ size_t t_n_extra_bits = ((t_save_buf_ndx * g_num_bits_per_byte) +
+ t_next_out_bit_shift);
+// set the number of saved bits
+ d_n_saved_bits = t_n_extra_bits;
+// remove the extra bits from the number to copy to the output buffer
+ t_frame_bit_ndx -= t_n_extra_bits;
+// find the actual output buf index, once we get there
+ t_next_out_buf_ndx -= t_save_buf_ndx;
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "Not enough output buffer space:\n" <<
+ "len (o_b) = " << t_noutput_bytes << " ==> " <<
+ t_n_extra_bits << " extra bit" <<
+ (t_n_extra_bits != 1 ? "s" : "") << " == " <<
+ t_save_buf_ndx << " Byte" <<
+ (t_save_buf_ndx != 1 ? "s" : "") << ", " <<
+ t_next_out_bit_shift << " bit" <<
+ (t_next_out_bit_shift != 1 ? "s" : "") << "\n";
+#endif
+// zero each output buffers' bytes
+ size_t t_n_zero = t_save_buf_ndx + (t_next_out_bit_shift ? 1 : 0);
+#if DO_PRINT_DEBUG_OUTPUT
+ size_t t_n_out_bytes = ((d_frame_size_bits / g_num_bits_per_byte) +
+ ((d_frame_size_bits % g_num_bits_per_byte) ? 1
: 0));
+ std::cout << "Zeroing save buffer from for " << t_n_zero <<
+ " Byte" << (t_n_zero != 1 ? "s" : "") << " (of " <<
+ d_frame_size_bits << " bit" <<
+ (d_frame_size_bits != 1 ? "s" : "") << " == " << t_n_out_bytes <<
+ " Byte" << (t_n_out_bytes != 1 ? "s" : "") << ")\n";
+#endif
+ for (size_t m = 0; m < d_n_code_inputs; m++)
+ bzero (d_save_buffer[m], t_n_zero);
+// loop over all extra bits
+ for (size_t n = t_n_extra_bits; n > 0; n--) {
+// first decrement the output bit & byte as necessary
+ if (--t_next_out_bit_shift < 0) {
+ t_next_out_bit_shift += g_num_bits_per_byte;
+ t_save_buf_ndx--;
+ }
+// get the encoder inputs to output
+ size_t t_inputs = t_out_buf->d_inputs;
+// loop over all code inputs (decoder-outputs), 1 bit per stream
+ for (size_t m = 0; m < d_n_code_inputs; m++) {
+ d_save_buffer[m][t_save_buf_ndx] |=
+ ((t_inputs & 1) << t_next_out_bit_shift);
+ t_inputs >>= 1;
+ }
+ t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+ }
+// at exit, "t_out_buf_ndx" should be == t_noutput_bytes, and
+// "t_out_bit_shift" should be 0; check these!
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "n_o_b_ndx (" << t_next_out_buf_ndx << ") ?=? " <<
+ "#o_B (" << t_noutput_bytes << ") & t_o_b_sh (" <<
+ t_next_out_bit_shift << ") ?=? 0\n";
+ assert (t_next_out_buf_ndx == t_noutput_bytes);
+ assert (t_next_out_bit_shift == 0);
+#endif
+ }
+// set the correct output buffer index and bit shift
+ t_out_bit_shift = t_next_out_bit_shift;
+ t_out_buf_ndx = t_next_out_buf_ndx;
+// copy any remaining bits looping backwards in bit-time
+// through the traceback trellis
+ for (size_t n = t_frame_bit_ndx; n > 0; n--) {
+// first decrement the output bit & byte as necessary
+ if (--t_out_bit_shift < 0) {
+ t_out_bit_shift += g_num_bits_per_byte;
+ t_out_buf_ndx--;
+ }
+// get the encoder inputs to output
+ size_t t_inputs = t_out_buf->d_inputs;
+// loop over all code inputs (decoder-outputs), 1 bit per stream
+ for (size_t m = 0; m < d_n_code_inputs; m++) {
+ out_buf[m][t_out_buf_ndx] |= ((t_inputs & 1) << t_out_bit_shift);
+ t_inputs >>= 1;
+ }
+ t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+ }
+// set the next output byte and bit-shift
+ t_out_bit_shift = t_next_out_bit_shift;
+ t_out_buf_ndx = t_next_out_buf_ndx;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Set FSM to fsm_dec_init\n";
+#endif
+ d_fsm = fsm_dec_init;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_output\n";
+#endif
+ break;
+ case (fsm_dec_init):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_init\n";
+#endif
+// this is called immediately (first input bit upon startup),
+// or after termination of a trellis.
+
+// reset states to the 0'th one
+ d_up_term_ndx = d_states_ndx = 0;
+// zero the metrics for those states
+ zero_metrics (0);
+#if 0
+// might not need to do this; check and see after it works
+// reset up_term states and number so that there is 1 item, the "0" state.
+ bzero (d_up_term_states_ndx[0], sizeof (size_t) * d_n_states);
+ bzero (d_up_term_states_ndx[1], sizeof (size_t) * d_n_states);
+#else
+ d_up_term_states_ndx[0][0] = 0;
+#endif
+// reset time count back to the start
+ d_time_count = 0;
+#if 0
+// reset the traceback structures
+// might not need to do this; check and see after it works
+ traceback_t_hdl t_out_bufs = d_out_buf;
+ for (size_t n = d_n_traceback_els; n > 0; n--) {
+ traceback_t_ptr t_out_buf = (*t_out_bufs++);
+ for (size_t m = d_n_states; m > 0; m--, t_out_buf++) {
+ t_out_buf->d_prev = NULL;
+ t_out_buf->d_inputs = -1;
+ }
+ }
+#endif
+// set the fsm to "doing up"
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Set FSM to fsm_dec_doing_up\n";
+#endif
+ d_fsm = fsm_dec_doing_up;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_init\n";
+#endif
+ break;
+// should never get here!
+ default:
+ assert (0);
+// done (switch) with FSM
+ }
+// done (while) there are inputs
+ }
+
+// consume all of the input items on all input streams
+// "ninput_items[]" doesn't seem to be reliable,
+// so compute this from the actual number of frames processed
+#if DO_PRINT_DEBUG_EXIT
+ std::cout << "Exiting FSM in state: " <<
+ (d_fsm == fsm_dec_init ? "init" :
+ (d_fsm == fsm_dec_doing_up ? "up" :
+ (d_fsm == fsm_dec_doing_middle ? "middle" :
+ (d_fsm == fsm_dec_doing_term ? "term" :
+ (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "\n" <<
+ "Consuming " << t_in_buf_ndx <<
+ " input items on each input stream (of " << t_ninput_items << ").\n";
+#endif
+ consume_each (t_in_buf_ndx);
+
+// make sure the number of output items makes sense
+// t_out_buf_ndx always points to the current index
+// t_out_bit_shift always points to the next bit position to be written
+ int t_leftover_bytes = t_out_buf_ndx % d_out_stream_el_size_bytes;
+ int t_leftover_bits = ((t_leftover_bytes * g_num_bits_per_byte) +
+ t_out_bit_shift);
+ int t_noutput_items = noutput_items;
+#if DO_PRINT_DEBUG_EXIT
+ std::cout << "Final o_b[" << t_out_buf_ndx << "][" <<
+ t_out_bit_shift << "] of " << t_noutput_bytes <<
+ ", el_size = " << d_out_stream_el_size_bytes <<
+ ", lo_Bytes = " << t_leftover_bytes <<
+ ", t_lo_bits = " << t_leftover_bits << "\n" <<
+ "Desired # output items = " << noutput_items << "\n";
+#endif
+ if (t_leftover_bits != 0) {
+ // should never get here!
+#if 1
+ assert (0);
+#else
+ int t_ndx = t_out_buf_ndx - t_leftover_bytes;
+ size_t t_n_copy = t_leftover_bytes + ((t_out_bit_shift != 0) ? 1 : 0);
+ assert (t_n_copy <= d_out_stream_el_size_bytes);
+// copy the leftover into the save buffer
+ for (size_t n = 0; n < d_n_code_inputs; n++) {
+ bcopy (&(out_buf[n][t_ndx]), d_save_buffer[n], t_n_copy);
+ }
+ t_noutput_items = t_ndx / d_out_stream_el_size_bytes;
+ d_n_saved_bits = t_leftover_bits;
+#if DO_PRINT_DEBUG_EXIT
+ std::cout << "Copied " << t_n_copy << " Byte" <<
+ (t_n_copy != 1 ? "s" : "") << " from o_b[][" << t_ndx <<
+ "] into each save buffer.\n" <<
+ "Actual #output items = " << t_noutput_items <<
+ ", # saved bit(s) = " << d_n_saved_bits << "\n";
+#endif
+#endif
+ }
+
+#if DO_TIME_THOUGHPUT
+ u_long d_t = end_timer (&t_tp);
+
+ std::cout << "dec_blk_conv_soft_full: Completed " << t_ninput_items <<
+ " bits in " << d_t << " usec => " <<
+ 1e6*(((double)(t_ninput_items))/((double) d_t)) <<
+ " b/s\n";
+#endif
+
+// returns number of items written to each output stream
+ return (t_noutput_items);
+}
Index: libecc/decoder_viterbi_block_full.h
===================================================================
RCS file: libecc/decoder_viterbi_block_full.h
diff -N libecc/decoder_viterbi_block_full.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libecc/decoder_viterbi_block_full.h 5 Jul 2006 17:49:58 -0000 1.1
@@ -0,0 +1,107 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_DECODER_VITERBI_BLOCK_FULL_H
+#define INCLUDED_DECODER_VITERBI_BLOCK_FULL_H
+
+#include <decoder_viterbi.h>
+
+class decoder_viterbi_block_full : public gr_block
+{
+/*!
+ * \brief Decode the incoming streams using a Viterbi-style decoder
+ *
+ * input: encoded data as soft symbols, either as individual
+ * streams or mux'ed into 1 stream.
+ *
+ * output: stream(s) of user-defined element size.
+ */
+
+public:
+ gr_decoder_viterbi_block_soft_full (int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> code_generator,
+ bool do_termination = true,
+ int start_memory_state = 0,
+ int end_memory_state = 0);
+
+ ~decoder_viterbi_block_soft_full ();
+
+ virtual void forecast (int noutput_items,
+ gr_vector_int &ninput_items_required);
+
+ virtual int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+ virtual int fixed_rate_noutput_to_ninput (int noutput_items);
+
+protected:
+
+/*
+ * state_get_from(v,i,k): use to retrieve a given bit-memory state,
+ * from the inputs:
+ *
+ * int v: the value from which to retrieve the given state
+ * int i: for which input stream (0 to #I-1)
+ * int k: the number of memory slots per input (e.g. 1+D^2 -> 2)
+ */
+
+ inline memory_t state_get_from(v,i,k) {
+ return (((v)>>((i)*(k)))&((1<<(k))-1));};
+
+/*
+ * state_add_to(s,i,v,k): use to create a given bit-memory state,
+ * from the inputs:
+ *
+ * int s: the state value to modify
+ * int i: for which input stream (0 to #I-1)
+ * int v: value to set the state to for this input
+ * int k: the number of memory slots per input (e.g. 1+D^2 -> 2)
+ */
+
+ inline void state_add_to(s,v,i,k) {(s)|=(((v)&((1<<(k))-1))<<((i)*(k)));};
+
+ void reset_metrics (u_char which);
+ void zero_metrics (u_char which);
+
+/*
+ * d_n_total_input_bits_per_stream: how many bits to store for each
+ * state to determine the best decoder-output (encoder-input) bits
+ */
+ size_t d_frame_size_bits;
+ size_t d_n_code_outputs, d_n_code_inputs, d_max_memory;
+ size_t d_time_count, d_n_total_input_bits_per_stream;
+ size_t d_n_saved_bits, d_n_saved_bits_start_ndx, d_n_traceback_els;
+ size_t d_n_states, d_n_input_combinations;
+ size_t d_states_ndx, d_up_term_ndx;
+ bool d_do_streaming, d_do_termination;
+ char **d_save_buffer;
+ state_t_ptr d_states[2];
+ fsm_dec_t d_fsm;
+ size_t* d_up_term_states_ndx[2];
+ traceback_t_hdl d_out_buf;
+};
+
+#endif /* INCLUDED_DECODER_VITERBI_BLOCK_FULL_H */
Index: libecc/decoder_viterbi_block_full_ic1.h
===================================================================
RCS file: libecc/decoder_viterbi_block_full_ic1.h
diff -N libecc/decoder_viterbi_block_full_ic1.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ libecc/decoder_viterbi_block_full_ic1.h 5 Jul 2006 17:49:58 -0000
1.1
@@ -0,0 +1,58 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_DECODER_VITERBI_BLOCK_FULL_IC1_IC1_H
+#define INCLUDED_DECODER_VITERBI_BLOCK_FULL_IC1_IC1_H
+
+#include <decoder_viterbi_block_full.h>
+
+class decoder_viterbi_block_full_ic1_ic1 : public decoder_viterbi_block_full
+{
+public:
+/*!
+ * class decoder_viterbi_block_full_ic1_ic1 :
+ * public decoder_viterbi_block_full
+ *
+ * Decode the incoming streams using a Viterbi-style decoder.
+ *
+ * output is "ic1": streams of char, one stream per output as defined
+ * by the instantiated code, using only the right-most justified
+ * bit as the single output bit per output item.
+ *
+ * The rest of the options are outlined in the inherited classes'
+ * header files.
+ */
+
+ inline decoder_viterbi_block_full_ic1 (int sample_precision,
+ encoder* l_encoder)
+ : decoder_viterbi_base (int sample_precision,
+ encoder* l_encoder) {};
+
+ virtual ~decoder_viterbi_block_full_ic1 () {};
+
+protected:
+ virtual void output_bit (char t_out_bit, char** out_buf,
+ size_t t_output_stream);
+ virtual void increment_counters (bool while_decoding);
+};
+
+#endif /* INCLUDED_DECODER_VITERBI_BLOCK_FULL_IC1_IC1_H */
Index: gr_decoder_viterbi_block_soft_full.cc
===================================================================
RCS file: gr_decoder_viterbi_block_soft_full.cc
diff -N gr_decoder_viterbi_block_soft_full.cc
--- gr_decoder_viterbi_block_soft_full.cc 3 Jul 2006 02:12:53 -0000
1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,1485 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio.
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gr_dec_blk_conv_soft_full.h>
-#include <gr_io_signature.h>
-#include <assert.h>
-#include <iostream>
-
-const int g_max_frame_size_bits = 10000000;
-const int g_max_num_streams = 10;
-const int g_num_bits_per_byte = 8;
-const int g_max_stream_el_size_bytes = 128;
-
-#define DO_TIME_THOUGHPUT 0
-#define DO_PRINT_DEBUG_INST 0
-#define DO_PRINT_DEBUG_INST_0 0
-#define DO_PRINT_DEBUG_INST_1 0
-#define DO_PRINT_DEBUG_INST_2 0
-#define DO_PRINT_DEBUG_FSM 0
-#define DO_PRINT_DEBUG_INIT 0
-#define DO_PRINT_DEBUG_UP 0
-#define DO_PRINT_DEBUG_UP_0 0
-#define DO_PRINT_DEBUG_UP_1 0
-#define DO_PRINT_DEBUG_MIDDLE 0
-#define DO_PRINT_DEBUG_MIDDLE_0 0
-#define DO_PRINT_DEBUG_MIDDLE_1 0
-#define DO_PRINT_DEBUG_TERM 0
-#define DO_PRINT_DEBUG_TERM_1 0
-#define DO_PRINT_DEBUG_OUTPUT 0
-#define DO_PRINT_DEBUG_OUTPUT_0 0
-#define DO_PRINT_DEBUG_EXIT 0
-#define DO_PRINT_DEBUG 0
-
-#if DO_TIME_THOUGHPUT
-#include <mld/mld_timer.h>
-#endif
-#if DO_PRINT_DEBUG
-#include <mld/n2bs.h>
-#endif
-
-gr_decoder_viterbi_block_soft_full_sptr
-gr_make_dec_blk_conv_soft_full
-(int frame_size_bits,
- int num_input_streams,
- int num_output_streams,
- std::vector<int> code_generator,
- bool do_termination)
-{
- return gr_decoder_viterbi_block_soft_full_sptr
- (new gr_decoder_viterbi_block_soft_full (frame_size_bits,
- num_input_streams,
- num_output_streams,
- code_generator,
- do_termination));
-}
-
-gr_decoder_viterbi_block_soft_full::gr_decoder_viterbi_block_soft_full
-(int frame_size_bits,
- int num_input_streams,
- int num_output_streams,
- std::vector<int> code_generator,
- bool do_termination)
- : gr_block ("dec_blk_conv_soft_full",
- gr_make_io_signature (0, 0, 0),
- gr_make_io_signature (0, 0, 0))
-{
-// make sure the frame length makes sense, #1 - more later
- if (frame_size_bits > g_max_frame_size_bits) {
- std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
- "Requested frame length (" << frame_size_bits <<
- " bits) must be at most " << g_max_frame_size_bits << " bits.\n";
- assert (0);
- }
-
-// check to make sure the number of input streams makes sense
- if ((n_code_inputs <= 0) | (n_code_inputs > g_max_num_streams)) {
- std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
- "Requested number of input streams (" <<
- n_code_inputs << ") must be between 1 and " <<
- g_max_num_streams << ".\n";
- assert (0);
- }
-
-// check to make sure the number of output streams makes sense
- if ((n_code_outputs <= 0) | (n_code_outputs > g_max_num_streams)) {
- std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
- "Requested number of output streams (" <<
- n_code_outputs << ") must be between 1 and " <<
- g_max_num_streams << ".\n";
- assert (0);
- }
-
-// make sure the code_generator is the correct length
- if (code_generators.size () !=
- ((size_t)(n_code_inputs * n_code_outputs))) {
- std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
- "Number of code generator entries (" << code_generators.size () <<
- ") is not equal to the product of the number of input and output" <<
- " streams (" << (n_code_inputs * n_code_outputs) << ").\n";
- assert (0);
- }
-
-// create the class frame variables
- d_frame_size_bits = frame_size_bits;
- d_out_stream_el_size_bytes = out_stream_el_size_bytes;
- d_n_code_inputs = n_code_inputs;
- d_n_code_outputs = n_code_outputs;
- d_do_streaming = (frame_size_bits == 0);
- d_do_termination = (d_do_streaming == true) ? false : do_termination;
- d_do_mux_inputs = do_mux_inputs;
-
-// allocate the vectors for doing the encoding. use 32-bit int's
-// actual bits to represent memory and the code, as it makes the
-// operations quite simple the state vectors.
-// code generates are for each I/O combination
-
- d_code_generators.resize (d_n_code_inputs * d_n_code_outputs, 0);
-
-// check the input code_generator for correctness & find the memory order
-// t_max_mem will be the mamimum number of memories used by the generator
-// t_code_ndx is a counter over all input code_generator elements
- int t_max_mem = 0, t_code_ndx = d_code_generators.size() - 1;
-// loop over all input streams first, output streams second
- for (int n = d_n_code_outputs - 1; n >= 0; n--) {
- int t_all_inputs_zero = 0;
- for (int m = d_n_code_inputs - 1; m >= 0; m--) {
- int t_in_code = code_generators[t_code_ndx];
- t_all_inputs_zero |= t_in_code;
- int t_code_mem = 0;
-// find the memory requirement for this code generator
- while (t_in_code != 0) {
- t_in_code >>= 1;
- t_code_mem++;
- }
- if (t_code_mem > t_max_mem)
- t_max_mem = t_code_mem;
-// store in d_code_generators in output-first ordering
- d_code_generators[(m*d_n_code_outputs) + n] =
- code_generators[t_code_ndx--];
- }
- if (t_all_inputs_zero == 0) {
- std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
- "At least 1 generator code for encode-output " << n+1 <<
- " must be non-0.\n";
- assert (0);
- }
- }
-
-// store the maximum memory order (e.g. "2" -> D^2)
- d_max_memory = t_max_mem - 1;
-
-// make sure the frame length makes sense, #2
- if (d_frame_size_bits < d_max_memory) {
- std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
- "Requested frame length (" << d_frame_size_bits <<
- " bit" << (d_frame_size_bits > 1 ? "s" : "") <<
- ") must be at least 1 memory length (" << d_max_memory <<
- " bit" << (d_max_memory > 1 ? "s" : "") <<
- " for this code).\n";
- assert (0);
- }
-
-// NOTE: d_n_states is a 'u_long', and thus is quite limited in terms
-// of max memory and # of input streams to 2^32 states
-// This is OK, since that many states would be impossibly slow to decode!
-// might make this a "long long" (64 bits) in the future
- d_n_states = 1 << (d_max_memory * d_n_code_inputs);
- d_n_input_combinations = 1 << d_n_code_inputs;
-
-#if DO_PRINT_DEBUG_INST_0
- std::cout << "Init:\n" <<
- "d_frame_size_bits = " << d_frame_size_bits << "\n" <<
- "d_out_stream_el_size_bytes = " << d_out_stream_el_size_bytes << "\n" <<
- "d_n_code_inputs = " << d_n_code_inputs << "\n" <<
- "d_n_code_outputs = " << d_n_code_outputs << "\n" <<
- "d_do_streaming = " <<
- ((d_do_streaming == true) ? "true" : "false") << "\n" <<
- "d_do_termination = " <<
- ((d_do_termination == true) ? "true" : "false") << "\n" <<
- "d_do_mux_inputs = " <<
- ((d_do_mux_inputs == true) ? "true" : "false") << "\n" <<
- "d_max_memory = " << d_max_memory << "\n" <<
- "d_n_states = " << d_n_states << "\n" <<
- "d_n_input_combinations = " << d_n_input_combinations << "\n";
-#endif
-
-// leave the output multiple at 1 (element); will save any incomplete
-// output data (int's) in "d_save_buffer"; all input data will be consumed
-
-// create the correct input signature
- int t_n_input_streams = ((d_do_mux_inputs == true) ?
- 1 : n_code_outputs);
-
- set_input_signature (gr_make_io_signature (t_n_input_streams,
- t_n_input_streams,
- sizeof (float)));
-// create the correct output signature
- set_output_signature (gr_make_io_signature (n_code_inputs,
- n_code_inputs,
- d_out_stream_el_size_bytes));
-#if DO_PRINT_DEBUG_INST_0
- std::cout <<
- "input_signature = [" << t_n_input_streams << ", " <<
- t_n_input_streams << ", " << sizeof (float) << "]\n" <<
- "output_signature = [" << n_code_outputs << ", " <<
- n_code_outputs << ", " << d_out_stream_el_size_bytes << "]\n";
-#endif
-
-// always start the fsm in the "init" state
- d_fsm = fsm_dec_init;
-
-// create a vector of indexes to states when doing "up" or "termination";
- d_up_term_states_ndx[0] = new size_t [d_n_states];
- d_up_term_states_ndx[1] = new size_t [d_n_states];
-
-// create the traceback buffers
-// get the total number of out bits per stream
- d_n_total_input_bits_per_stream = d_frame_size_bits;
- if (d_do_termination == true)
- d_n_total_input_bits_per_stream += d_max_memory;
- d_n_traceback_els = d_n_total_input_bits_per_stream + 1;
-// create the output buffers:
-// this is a 2d matrix structure, where the first dimension
-// is the number of output bits; the second dimension is
-// the number of states.
-// When doing full frames (no tau), each bit-time's state's traceback
-// contains just the pointer to the previous bit-time's state's traceback
-// as well as the inputs for that connection.
-// No further work is required because each reverse-path is unique
-// once a given end-bit-time's state is determined to be "the one"
- traceback_t_hdl t_out_buf =
- d_out_buf = new traceback_t_ptr [d_n_traceback_els];
- for (size_t n = d_n_traceback_els; n > 0; n--) {
- (*t_out_buf++) = new traceback_t [d_n_states];
- }
-
- // create the save buffers
- char** t_save_buffer = d_save_buffer = new char* [d_n_code_inputs];
- size_t t_n_out_bytes = ((d_frame_size_bits / g_num_bits_per_byte) +
- ((d_frame_size_bits % g_num_bits_per_byte) ? 1 : 0));
- for (size_t n = 0; n < d_n_code_inputs; n++) {
- (*t_save_buffer++) = new char [t_n_out_bytes];
- }
-
-// reset the number of saved bits
- d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
-
-// setup the internal structures for exiting and entering states
-
-#if DO_PRINT_DEBUG_INST_0
- std::cout <<
- "d_n_total in bits / stream = " << d_n_total_input_bits_per_stream << "\n"
<<
- "d_n_traceback_els = " << d_n_traceback_els << "\n" <<
- "t_n_out_bytes / stream = " << t_n_out_bytes << "\n";
-#endif
-
-// Find the approximate output rate / input rate
-// each input item produces 1 bit of an output item w/o termination
- double t_rel_rate = (double)(d_out_stream_el_size_bytes *
g_num_bits_per_byte);
- if (d_do_termination == true) {
-// include termination bits
- t_rel_rate *= (((double) d_frame_size_bits) /
- ((double) d_n_total_input_bits_per_stream));
- }
-// Set the approximate output rate / input rate
- set_relative_rate (t_rel_rate);
-
-// 'new' everything first; no connections yet
- state_t_ptr t_state = d_states[0] = new state_t [d_n_states];
- for (size_t n = d_n_states; n > 0; n--, t_state++) {
- connection_t_ptr t_connection = t_state->d_connections
- = new connection_t [d_n_input_combinations];
- for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
- t_connection->d_output_bits = new float [d_n_code_outputs];
- }
- }
-
-// 'new' everything first; no connections yet
- t_state = d_states[1] = new state_t [d_n_states];
- for (size_t n = d_n_states; n > 0; n--, t_state++) {
- connection_t_ptr t_connection = t_state->d_connections
- = new connection_t [d_n_input_combinations];
- for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
- t_connection->d_output_bits = new float [d_n_code_outputs];
- }
- }
-
-// temporary memory and mask for output bit computations
- size_t t_memory[d_n_code_inputs];
- size_t t_memory_mask = ((2 << d_max_memory) - 1) ^ 1;
-
-#if DO_PRINT_DEBUG
- size_t t_state_print_bits = (d_max_memory * d_n_code_inputs) + 1;
- size_t t_mem_print_bits = d_max_memory + 2;
-
- std::cout << "Setting States and Connections\n";
-#endif
-
-// loop over all possible memory states
- state_t_ptr t_state0 = d_states[0];
- state_t_ptr t_state1 = d_states[1];
- for (size_t n = 0; n < d_n_states; n++, t_state0++, t_state1++) {
-#if DO_PRINT_DEBUG_INST_1
- std::cout << "Starting state # " << n << " == " <<
- n2bs (n, t_state_print_bits) << "\n";
-#endif
-// retrieve the memory values for this state
-// probably a faster way to do this, but since this is
-// executed only upon instantiation, whatever.
- size_t* t_mem_ptr = t_memory;
- for (size_t p = 0; p < d_n_code_inputs; p++) {
- int t_mem = state_get_from (n, p, d_max_memory);
-#if DO_PRINT_DEBUG_INST_1
- std::cout << "s_g_f (" <<
- n2bs (n, t_state_print_bits) << ", " <<
- p << ", " << d_max_memory << ") => t_m = " <<
- n2bs (t_mem, t_mem_print_bits) << "\n";
-#endif
-// shift them by 1 (and mask) to make updating for all inputs simple
- (*t_mem_ptr++) = t_mem << 1;
-#if DO_PRINT_DEBUG_INST_1
- std::cout << "t_m_p[" << p << "] = " <<
- n2bs (t_mem << 1, t_mem_print_bits) << " == (" <<
- n2bs (t_mem, t_mem_print_bits) << " << 1)\n";
-#endif
- }
-
-// loop over all possible input values, 1 bit per input stream
- connection_t_ptr t_connection0 = t_state0->d_connections;
- connection_t_ptr t_connection1 = t_state1->d_connections;
- for (size_t q = 0; q < d_n_input_combinations;
- q++, t_connection0++, t_connection1++) {
-#if DO_PRINT_DEBUG_INST_1
- std::cout << "Starting inputs " << q << " == " <<
- n2bs (q, d_n_code_inputs + 1) << "\n";
-#endif
-
-// update memory for this set of inputs
- t_mem_ptr = t_memory;
- size_t t_this_input = q;
-
-// loop over all code inputs, and update just the single input bit
- for (size_t r = d_n_code_inputs; r > 0; r--) {
- int t_mem = (*t_mem_ptr) & t_memory_mask;
-#if DO_PRINT_DEBUG_INST_1
- std::cout << "t_m = " << n2bs (t_mem, t_mem_print_bits) <<
- " == " << n2bs (*t_mem_ptr, t_mem_print_bits) <<
- " & " << n2bs (t_memory_mask, t_mem_print_bits) << "\n";
-#endif
- (*t_mem_ptr++) = t_mem | (t_this_input & 1);
-#if DO_PRINT_DEBUG_INST_1
- std::cout << "t_m_p[" << (d_n_code_inputs - r) << "] = " <<
- n2bs (t_mem | (t_this_input & 1), t_mem_print_bits) <<
- " == t_m | " << (t_this_input & 1) << "\n";
-#endif
- t_this_input >>= 1;
- }
-
-// got the updated memory for this particular state & inputs
-// recreate the "to" state from the updated memory
- t_mem_ptr = t_memory;
- size_t t_out_state = 0;
- for (size_t p = 0; p < d_n_code_inputs; p++) {
-#if DO_PRINT_DEBUG_INST_1
- std::cout << "s_a_t (" <<
- n2bs (t_out_state, t_state_print_bits) <<
- ", " << n2bs (*t_mem_ptr, t_mem_print_bits) << ", " << p <<
- ", " << d_max_memory << ") ==> t_o_s out = ";
-#endif
- state_add_to (t_out_state, *t_mem_ptr++, p, d_max_memory);
-#if DO_PRINT_DEBUG_INST_1
- std::cout << n2bs (t_out_state, t_state_print_bits) << "\n";
-#endif
- }
-
-// get the "to" state pointers from d_states[0] to [1]
- state_t_ptr t_to_state = &(d_states[1][t_out_state]);
- t_connection0->d_to = t_to_state;
- t_connection0->d_to_ndx = t_out_state;
- float* t_output_bit0 = t_connection0->d_output_bits;
-
-// get the "to" state pointers from d_states[1] to [0]
- t_to_state = &(d_states[0][t_out_state]);
- t_connection1->d_to = t_to_state;
- t_connection1->d_to_ndx = t_out_state;
- float* t_output_bit1 = t_connection1->d_output_bits;
-
-// determine the ideal output values: loop over all outputs
- size_t t_vec_ctr = 0;
- for (size_t s = 0; s < d_n_code_outputs; s++) {
-
-// loop over all inputs, xor'ing the result each time
- int t_out_result = 0;
- t_mem_ptr = t_memory;
- for (size_t t = 0; t < d_n_code_inputs; t++) {
-#if DO_PRINT_DEBUG_INST_1
- std::cout << "b_i = " << n2bs (t_out_result, t_mem_print_bits) <<
- ", st[" << t << "] = " << n2bs ((*t_mem_ptr), t_mem_print_bits) <<
- ", cg[" << t_vec_ctr << "] = " <<
- n2bs (d_code_generators[t_vec_ctr], t_mem_print_bits) <<
- ", st[] & cg[] = " << n2bs ((*t_mem_ptr) &
- d_code_generators[t_vec_ctr],
- t_mem_print_bits);
-#endif
- t_out_result ^= ((*t_mem_ptr++) &
- d_code_generators[t_vec_ctr++]);
-#if DO_PRINT_DEBUG_INST_1
- std::cout << ", b_o = " <<
- n2bs (t_out_result, t_mem_print_bits) << '\n';
-#endif
- }
-#if DO_PRINT_DEBUG_INST_1
- std::cout << "b_r = " << n2bs (t_out_result, t_mem_print_bits);
-#endif
-// sum the number of set bits, mod 2, for the output bit
- size_t t_out_bit = t_out_result & 1;
- for (size_t v = d_max_memory; v > 0; v--) {
- t_out_result >>= 1;
- t_out_bit ^= (t_out_result & 1);
- }
-
-// store the result for this particular output stream,
-// converting the bit 1 -> +1.0, and 0 -> -1.0
- float t_out_value = (float)(((int)(t_out_bit << 1)) - 1);
- *t_output_bit0++ = t_out_value;
- *t_output_bit1++ = t_out_value;
-#if DO_PRINT_DEBUG_INST_1
- std::cout << ", o_v = " << t_out_value << "\n";
-#endif
-
-// finished (for) all output values
- }
-// finished (for) over all possible input values
- }
-// finished (for) over all possible states
- }
-
-// so now d_states is/are completely populated!
-// These make for simple access to looping over all possible inputs or
-// outputs for a given state to determine what the path with the best
-// metric is.
-
-#if DO_PRINT_DEBUG_INST_2
-// loop over all possible memory states
- std::cout << "State Tables\n";
- t_state0 = d_states[0];
- t_state1 = d_states[1];
- for (size_t n = 0; n < d_n_states; n++, t_state0++, t_state1++) {
- std::cout << "d_s[0][" << n << "] = " << t_state0 << "\n";
-// loop over all possible input values, 1 bit per input stream
- connection_t_ptr t_connection0 = t_state0->d_connections;
- for (size_t q = 0; q < d_n_input_combinations; q++, t_connection0++) {
- std::cout << "s0[" << n2bs (n, t_state_print_bits) << "][" <<
- n2bs (q, d_n_code_inputs+1) << "] = " << t_connection0 <<
- " -> s1[" << n2bs (t_connection0->d_to_ndx, t_state_print_bits) <<
- "] = " << t_connection0->d_to << "\n";
- }
- std::cout << "d_s[1][" << n << "] = " << t_state1 << "\n";
- connection_t_ptr t_connection1 = t_state1->d_connections;
- for (size_t q = 0; q < d_n_input_combinations; q++, t_connection1++) {
- std::cout << "s1[" << n2bs (n, t_state_print_bits) << "][" <<
- n2bs (q, d_n_code_inputs+1) << "] = " << t_connection1 <<
- " -> s0[" << n2bs (t_connection1->d_to_ndx, t_state_print_bits) <<
- "] = " << t_connection1->d_to << "\n";
- }
- }
-
- traceback_t_hdl t_out_bufs = d_out_buf;
- for (size_t n = 0; n < d_n_traceback_els; n++, *t_out_bufs++) {
- traceback_t_ptr t_out_buf = *t_out_bufs;
- for (size_t m = 0; m < d_n_states; m++, t_out_buf++) {
- std::cout << "tb[" << n << "] = " << t_out_bufs <<
- ", &tb[" << n << "][" << m << "] = " << (&d_out_buf[n][m]) <<
- ", tb[" << n << "," << m << "] = " << t_out_buf << "\n";
- }
- }
-
- std::cout << "Done with instantiation.\n";
-#endif
-}
-
-gr_decoder_viterbi_block_soft_full::~gr_decoder_viterbi_block_soft_full
-()
-{
-// reverse over from allocation
-
- delete [] d_up_term_states_ndx[0];
- delete [] d_up_term_states_ndx[1];
-
-// delete the state's structures
- state_t_ptr t_state = d_states[0];
- for (size_t n = d_n_states; n > 0; n--, t_state++) {
- connection_t_ptr t_connection = t_state->d_connections;
- for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
- delete [] t_connection->d_output_bits;
- }
- delete [] t_state->d_connections;
- }
- delete [] d_states[0];
-
- t_state = d_states[1];
- for (size_t n = d_n_states; n > 0; n--, t_state++) {
- connection_t_ptr t_connection = t_state->d_connections;
- for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
- delete [] t_connection->d_output_bits;
- }
- delete [] t_state->d_connections;
- }
- delete [] d_states[1];
-
-// delete the save buffer
- char** t_save_buffer = d_save_buffer;
- for (size_t n = 0; n < d_n_code_inputs; n++) {
- delete [] (*t_save_buffer++);
- }
- delete [] d_save_buffer;
-
-// delete the output buffer
- traceback_t_hdl t_out_buf = d_out_buf;
- for (size_t n = d_n_traceback_els; n > 0; n--) {
- delete [] (*t_out_buf++);
- }
- delete [] d_out_buf;
-}
-
-void gr_decoder_viterbi_block_soft_full::reset_metrics (u_char which)
-{
- state_t_ptr t_state = d_states[which&1];
- for (size_t n = d_n_states; n > 0; n--, t_state++) {
- t_state->d_max_metric = -1e10;
-#if 0
-// probably don't need to do these, try removing them later
- t_state->d_max_state_ndx = 0;
- t_state->d_max_input = -1;
-#endif
- }
-}
-
-void gr_decoder_viterbi_block_soft_full::zero_metrics (u_char which)
-{
- state_t_ptr t_state = d_states[which&1];
- for (size_t n = d_n_states; n > 0; n--, t_state++) {
- t_state->d_max_metric = 0;
-#if 0
-// probably don't need to do these, try removing them later
- t_state->d_max_state_ndx = -1;
- t_state->d_max_input = -1;
-#endif
- }
-}
-
-void gr_decoder_viterbi_block_soft_full::forecast
-(int noutput_items,
- gr_vector_int &ninput_items_required)
-{
- int ninput_items = fixed_rate_noutput_to_ninput (noutput_items);
-
- int ninputs = ninput_items_required.size();
- for (int n = 0; n < ninputs; n++)
- ninput_items_required[n] = ninput_items;
-}
-
-/*
- * Compute the number of input items (soft symbols [floats]) needed to produce
- * 'noutput' items (elements). For convolutional decoders, there is 1
- * bit output per bit input per stream, with the addition of a some
- * bits for trellis termination if selected. Without termination,
- * there is exactly 1:1 input to output (1 symbol in to 1 bit out),
- * no matter the encoding type.
- *
- * if (not terminating), then get the number of output bytes.
- *
- * otherwise, find the number of frames (not necessarily and integer),
- * and then compute the number of input bits (including termination)
- * required to produce those frames. Subtract the number of bits
- * leftover from the previous computation, then find the number of input
- * elements (soft symbols), ceil'd to make sure there are enough.
- *
- * finally, if the input streams are mux'ed, then multiply by the
- * number of inputs.
- */
-
-int
-gr_decoder_viterbi_block_soft_full::fixed_rate_noutput_to_ninput
-(int noutput_items)
-{
- int t_ninput_items = 0;
- int t_noutput_bits = (noutput_items * d_out_stream_el_size_bytes *
- g_num_bits_per_byte) - d_n_saved_bits;
-// if there are enough saved bits, just use those, no inputs required
- if (t_noutput_bits <= 0)
- return (t_ninput_items);
-
-// remove any bits already in the decoding trellis
- if (d_time_count != 0) {
- int t_time_bits = ((d_time_count > d_frame_size_bits) ? 0 :
- d_frame_size_bits - d_time_count);
- t_noutput_bits -= t_time_bits;
- t_ninput_items += t_time_bits;
- }
-// if completing this trellis doesn't create enough outputs ...
- if (t_noutput_bits > 0) {
-
-// there is a 1:1 ratio between input symbols and output bits (per
-// stream), except for termination bits which are already taken into
-// account in the total # of input bits per stream class variable;
-// need to round the # output bits to the
-
-// find the number of frames, ceil'd to the next higher integer
- int t_nframes = (int) ceilf (((float) t_noutput_bits) /
- ((float) d_frame_size_bits));
-// find the number of required input bits
- t_ninput_items += t_nframes * d_n_total_input_bits_per_stream;
- }
-
-// if doing mux'ing, there are more elements in the single input
- if (d_do_mux_inputs == true) {
- t_ninput_items *= d_n_code_outputs;
- }
- return (t_ninput_items);
-}
-
-int
-gr_decoder_viterbi_block_soft_full::general_work
-(int noutput_items,
- gr_vector_int &ninput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items)
-{
-#if DO_TIME_THOUGHPUT
- struct timeval t_tp;
- start_timer (&t_tp);
-#endif
-#if DO_PRINT_DEBUG
- size_t t_state_print_bits = (d_max_memory * d_n_code_inputs) + 1;
- size_t t_mem_print_bits = d_max_memory + 2;
-#endif
-// setup variables for quicker access
- const float **in_buf = (const float **) &input_items[0];
- char **out_buf = (char **) &output_items[0];
- int t_in_buf_ndx = 0, t_out_buf_ndx = 0;
- int t_out_bit_shift = 0;
- int t_ninput_items = fixed_rate_noutput_to_ninput (noutput_items);
- int t_noutput_bytes = noutput_items * d_out_stream_el_size_bytes;
-
-#if DO_PRINT_DEBUG_INST
- std::cout << "# output items = " << noutput_items << " (" <<
- t_noutput_bytes << " Bytes, " << (t_noutput_bytes * g_num_bits_per_byte) <<
- " bits), # input items = " << t_ninput_items << " Symbols\n";
- for (size_t n = 0; n < ninput_items.size(); n++) {
- std::cout << "# input items [" << n << "] = " << ninput_items[n] << "\n";
- }
-#endif
-
-// put any leftover bits into the output
- if (d_n_saved_bits != 0) {
-// copy the leftover from the save buffer
-// check to make sure it will all fit
- size_t t_noutput_bits = t_noutput_bytes * g_num_bits_per_byte;
- size_t t_n_copy;
- if (t_noutput_bits < d_n_saved_bits) {
-// asking for fewer bits than available; set to copy
-// just what's being asked for
- t_n_copy = t_noutput_bytes;
- } else {
-// asking for at least as many bits as available; set to copy all
- t_out_buf_ndx = d_n_saved_bits / g_num_bits_per_byte;
- t_out_bit_shift = d_n_saved_bits % g_num_bits_per_byte;
- t_n_copy = t_out_buf_ndx + (t_out_bit_shift != 0 ? 1 : 0);
- }
-// do the copy for all output streams (code inputs)
-// copy starting at save buffer index "start"
- for (size_t n = 0; n < d_n_code_inputs; n++)
- bcopy (&(d_save_buffer[n][d_n_saved_bits_start_ndx]),
- out_buf[n], t_n_copy);
-#if DO_PRINT_DEBUG_INST
- std::cout << "Copied " << t_n_copy << " Byte" <<
- (t_n_copy != 1 ? "s" : "") << ": s_b[][" <<
- d_n_saved_bits_start_ndx << "] => o_b[][0]\n" <<
- "# saved bits = " << d_n_saved_bits <<
- ", o_b_ndx = " << t_out_buf_ndx <<
- ", bit shift = " << t_out_bit_shift << "\n";
-#endif
-// update the number of saved bits and start
- if (t_noutput_bits < d_n_saved_bits) {
-// asking for fewer bit than available: update
-// the number of saved bits and their starting index
- d_n_saved_bits_start_ndx += t_noutput_bytes;
- d_n_saved_bits -= (t_noutput_bytes * g_num_bits_per_byte);
-#if DO_PRINT_DEBUG_INST
- std::cout << "Updated # saved bits = " << d_n_saved_bits <<
- ", index = " << d_n_saved_bits_start_ndx << "\n";
-#endif
-// nothing to consume; return the desired number of output items
- return (noutput_items);
- } else {
- d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
- }
- }
-#if DO_PRINT_DEBUG_INST
- std::cout << "Starting FSM in state: " <<
- (d_fsm == fsm_dec_init ? "init" :
- (d_fsm == fsm_dec_doing_up ? "up" :
- (d_fsm == fsm_dec_doing_middle ? "middle" :
- (d_fsm == fsm_dec_doing_term ? "term" :
- (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "\n";
-#endif
-
-// while there are input items to create
- while (t_out_buf_ndx < t_noutput_bytes) {
-#if DO_PRINT_DEBUG_FMS
- std::cout << "Starting 'while': processing " << t_in_buf_ndx << " of " <<
- t_ninput_items << " items.\nJumping to state '" <<
- (d_fsm == fsm_dec_init ? "init" :
- (d_fsm == fsm_dec_doing_up ? "up" :
- (d_fsm == fsm_dec_doing_middle ? "middle" :
- (d_fsm == fsm_dec_doing_term ? "term" :
- (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "'\n";
-#endif
-// jump to the correct state in the fsm
- switch (d_fsm) {
- case fsm_dec_doing_up:
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Starting fsm_dec_doing_up\n";
-#endif
-// set the number of up_down indices
- size_t t_n_up_down_ndx = 1 << (d_n_code_inputs *
- d_time_count);
-// stay in this state until the correct number of input symbols are
-// reached; exit also if we run out of input symbols to process
- while ((d_time_count < d_max_memory) &
- (t_in_buf_ndx < t_ninput_items)) {
-#if DO_PRINT_DEBUG_UP_0
- std::cout << "Doing 'while' loop:\n" <<
- "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" <<
- "d_time_count = " << d_time_count << "\n" <<
- "d_max_memory = " << d_max_memory << "\n" <<
- "t_in_buf_ndx = " << t_in_buf_ndx << "\n" <<
- "t_ninput_items = " << t_ninput_items << "\n";
-#endif
-// use the "from" states, loop over all inputs and compute the metric for
-// each & store it in the "to" state at the end of the connection.
-// no need to compare metrics yet, since none join into any given state
-
-#if 0
-// reset the "to" state's metrics
-// probably don't need to do this; try removing later
- reset_metrics (d_states_ndx ^ 1);
-#if DO_PRINT_DEBUG_UP
- std::cout << "Reset Metrics\n";
-#endif
-#endif
-
-// reset the state's index for each set of new inputs
- size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
- size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
-// loop over all current stored "up" states
- for (size_t n = 0; n < t_n_up_down_ndx; n++) {
- size_t t_state_ndx = *t_state_ndx_ptr++;
-// get a pointer to this state's structure
- state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
-// get the connections for all inputs
- connection_t_ptr t_connection = t_state->d_connections;
-#if DO_PRINT_DEBUG_UP_0
- std::cout << "Looping over all 'up' states:\n" <<
- "n = " << n << "\n" <<
- "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" <<
- "d_states_ndx = " << d_states_ndx << "\n" <<
- "t_state_ndx = " << t_state_ndx << "\n" <<
- "d_n_input_combs = " << d_n_input_combinations << "\n" <<
- "t_state = " << t_state << "\n" <<
- "t_connection = " << t_connection << "\n";
-#endif
-// loop over all possible input values, 1 bit per input stream
- for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
-// find the "to" state for this connection
- state_t_ptr t_to_state = t_connection->d_to;
-// get the output bits for this connection
- float* t_output_bit = t_connection->d_output_bits;
-// start with this state's metric
- float t_metric = t_state->d_max_metric;
-#if DO_PRINT_DEBUG_UP_0
- std::cout <<
- "to state index = " << t_connection->d_to_ndx << "\n" <<
- "current metric = " << t_metric << "\n";
-#endif
- if (d_do_mux_inputs == true) {
-// if using mux'ed input streams, handle differently
- const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
-// loop over all encoder-output values
- for (size_t r = d_n_code_outputs; r > 0; r--) {
-#if DO_PRINT_DEBUG_UP
- std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
- *t_output_bit << " ==> metric -> ";
-#endif
- t_metric += ((*t_in_buf++) * (*t_output_bit++));
-#if DO_PRINT_DEBUG_UP
- std::cout << t_metric << "\n";
-#endif
- }
- } else {
-// loop over all encoder-output values
- for (size_t r = 0; r < d_n_code_outputs; r++) {
-#if DO_PRINT_DEBUG_UP
- std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
- ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
-#endif
- t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
-#if DO_PRINT_DEBUG_UP
- std::cout << t_metric << "\n";
-#endif
- }
- }
-// get the "to" state index
- size_t t_to_ndx = t_connection->d_to_ndx;
-// store the metric in the "to" state; should not have been used before
- t_to_state->d_max_metric = t_metric;
-// add the "to" state index to the "up" state list
- *t_next_state_ndx_ptr++ = t_to_ndx;
-// update the traceback structure, depending on which variety it is
-// doing full trellis before decoding; use d_out_buf
-// simple: get the current state & output state
- traceback_t_ptr t_out_buf = &(d_out_buf[d_time_count]
- [t_state_ndx]);
- traceback_t_ptr t_next_out_buf = &(d_out_buf[d_time_count+1]
- [t_to_ndx]);
-#if DO_PRINT_DEBUG_UP_1
- std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n" <<
- "ndx[" << n << "] == " << t_state_ndx <<
- ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
- "]: max_ndx = " <<
- n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
- ", input = " << n2bs(q, d_n_code_inputs+1) <<
- ": " << t_next_out_buf << " => " << t_out_buf << "\n";
-#endif
-// and connect output to the current, set inputs on output
- t_next_out_buf->d_prev = t_out_buf;
- t_next_out_buf->d_inputs = q;
-// finished (for) this input value
- }
-// finished (for) this "up_term" state
- }
-// increment the in_buf index, depending on mux'ing or not
- t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
-// increment the time counter
- d_time_count++;
-// update the number of "up_term" states
- d_up_term_ndx ^= 1;
-// increase the number of using states
- t_n_up_down_ndx <<= d_n_code_inputs;
-// change which d_states' index to use as starting
- d_states_ndx ^= 1;
-// finished (while) staying in this fsm state or not
- }
-// if reached the end of doing the "up" part of the trellis,
-// switch states into the middle
- if (d_time_count == d_max_memory) {
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Setting FSM to fsm_dec_doing_middle\n";
-#endif
- d_fsm = fsm_dec_doing_middle;
- }
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Exited fsm_dec_doing_up\n";
-#endif
- break;
- case (fsm_dec_doing_middle):
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Entered fsm_dec_doing_middle\n";
-#endif
-// stay in this state until the correct number of input symbols is
-// reached (if doing block coding), or until there are no more input
-// symbols to parse
- while (((d_frame_size_bits != 0) &
- (d_time_count < d_frame_size_bits) &
- (t_in_buf_ndx < t_ninput_items)) |
- ((d_frame_size_bits == 0) &
- (t_in_buf_ndx < t_ninput_items))) {
-// use all states, loop over all inputs, compute the metric for
-// each; compare the current metric with all previous stored metric in the
-// endpoint of the connection to find the highest one.
-
-// reset the "to" state's metrics
- reset_metrics (d_states_ndx ^ 1);
-// get the state's index for each set of new inputs
- state_t_ptr t_state = d_states[d_states_ndx];
-#if DO_PRINT_DEBUG_MIDDLE
- std::cout << "Time Count " << (d_time_count+1) << " of " <<
- d_frame_size_bits << "\n" <<
- "d_states_ndx = " << d_states_ndx << "\n";;
-#endif
-// loop over all current states
- for (size_t n = 0; n < d_n_states; n++, t_state++) {
-// loop over all possible input values, 1 bit per input stream
- connection_t_ptr t_connection = t_state->d_connections;
-#if DO_PRINT_DEBUG_MIDDLE_0
- std::cout << "Looping over all 'middle' states: " <<
- n << " of " << d_n_states << "\n";
-#endif
- for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
-#if DO_PRINT_DEBUG_MIDDLE_0
- std::cout << "Input = " << n2bs(q, d_n_code_inputs+1) << "\n";
-#endif
-// start with this state's metric
- float t_metric = t_state->d_max_metric;
-// get the "to" state
- state_t_ptr t_to_state = t_connection->d_to;
-// get that state's metric
- float t_to_metric = t_to_state->d_max_metric;
-// see if the computation is even needed;
-// maximum change is d_n_code_outputs if all bits match exactly
- if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
-#if DO_PRINT_DEBUG_MIDDLE_0
- std::cout << "!not computing metric!\n";
-#endif
- continue;
- }
-// metrics are close enough; do the computation and the compare
-// get the output bits for this connection
- float* t_output_bit = t_connection->d_output_bits;
- if (d_do_mux_inputs == true) {
-// if using mux'ed input streams, handle differently
- const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
-// loop over all encoder-output values
- for (size_t r = d_n_code_outputs; r > 0; r--) {
-#if DO_PRINT_DEBUG_MIDDLE_0
- std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
- *t_output_bit << " ==> metric -> ";
-#endif
- t_metric += ((*t_in_buf++) * (*t_output_bit++));
-#if DO_PRINT_DEBUG_MIDDLE_0
- std::cout << t_metric << "\n";
-#endif
- }
- } else {
-// loop over all encoder-output values
- for (size_t r = 0; r < d_n_code_outputs; r++) {
-#if DO_PRINT_DEBUG_MIDDLE_0
- std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
- ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
-#endif
- t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
-#if DO_PRINT_DEBUG_MIDDLE_0
- std::cout << t_metric << "\n";
-#endif
- }
- }
-// done with this input value; compare old and new metrics
- if (t_metric > t_to_metric) {
-#if DO_PRINT_DEBUG_MIDDLE
- std::cout << "New Metric to s[" <<
- n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
- if (t_to_state->d_max_metric == -1e10) {
- std::cout << "setting to ";
- } else {
- std::cout << "was s[" <<
- n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
- "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
- "]@ " << t_to_state->d_max_metric << " now ";
- }
- std::cout << "s[" << n2bs(n,t_state_print_bits) << "] i[" <<
- n2bs (q, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
-#endif
-// new metric is better; copy that info into the "to" state
- t_to_state->d_max_metric = t_metric;
- t_to_state->d_max_state_ndx = n;
- t_to_state->d_max_input = q;
- }
-// finished (for) this input value
- }
-// finished (for) this state
- }
-// done with all states and all inputs; now update the traceback structure
-// change which d_states' index to use as starting
- d_states_ndx ^= 1;
-// get the state's index for the "to" set of new inputs to get the
-// "max" stuff from
- t_state = d_states[d_states_ndx];
-// update the traceback structure
-// loop over all current states
- traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
- traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
-#if DO_PRINT_DEBUG_MIDDLE_1
- std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
-#endif
- for (size_t n = d_n_states; n > 0; n--, t_state++) {
-// simple: get the current state & output state
-// and connect output to the current, set inputs on output
- traceback_t_ptr t_out_buf = t_out_bufs++;
- traceback_t_ptr t_prev_out_buf =
- &(t_prev_out_bufs[t_state->d_max_state_ndx]);
-#if DO_PRINT_DEBUG_MIDDLE_1
- std::cout << "s[" << n2bs(d_n_states-n,t_state_print_bits) <<
- "]: max_ndx = " <<
- n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
- ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
- ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
-#endif
- t_out_buf->d_prev = t_prev_out_buf;
- t_out_buf->d_inputs = t_state->d_max_input;
-// finished doing this state
- }
-// increment the in_buf index, depending on mux'ing or not
- t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
-// increment the time counter
- d_time_count++;
-// finished (while) staying in this fsm state or not
- }
- if ((d_frame_size_bits != 0) &
- (d_time_count == d_frame_size_bits)) {
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Setting FSM to fsm_dec_doing_term\n";
-#endif
- d_fsm = fsm_dec_doing_term;
- }
- break;
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Exited fsm_dec_doing_middle\n";
-#endif
- case (fsm_dec_doing_term):
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Entered fsm_dec_doing_term\n";
-#endif
-// set the "next" up_down index to the end of their states
- size_t t_time_count = d_max_memory - (d_time_count - d_frame_size_bits);
- t_n_up_down_ndx = 1 << (d_n_code_inputs * t_time_count);
-// stay in this state until the correct number of input symbols are
-// reached; exit also if we run out of input symbols to process
- while ((t_time_count > 0) &
- (t_in_buf_ndx < t_ninput_items)) {
-#if DO_PRINT_DEBUG_TERM
- std::cout << "Doing time " << (d_max_memory - t_time_count + 1) <<
- " of " << d_max_memory << "; starting buf[" << t_in_buf_ndx <<
- "] of [" << t_ninput_items << "]\n";
-#endif
-// use the "to" states,
-// FIXME: loop over just the "0" inputs
-// and compute the metric for
-// each, compare & store it in the "to" state at the end of the connection.
-
-// reset the "to" state's metrics
- reset_metrics (d_states_ndx ^ 1);
-// reset the state's index for each set of new inputs
- size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
- size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
-// loop over all current stored "term" state indeces
- for (size_t n = 0; n < t_n_up_down_ndx; n++) {
- size_t t_state_ndx = *t_state_ndx_ptr++;
- state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
-// loop over just the all 0 input value (d_connections[0])
- connection_t_ptr t_connection = t_state->d_connections;
-// get the "to" state
- state_t_ptr t_to_state = t_connection->d_to;
-// start with this state's metric
- float t_metric = t_state->d_max_metric;
-// get that state's metric
- float t_to_metric = t_to_state->d_max_metric;
-#if DO_PRINT_DEBUG_TERM
- std::cout << "Term state " << (n+1) << " of " << t_n_up_down_ndx <<
- "; using d_s[" << d_states_ndx << "][" <<
- n2bs(t_state_ndx,t_state_print_bits) << "]\n";
-#endif
-// see if the computation is even needed;
-// maximum change is d_n_code_outputs if all bits match exactly
- if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
-#if DO_PRINT_DEBUG_TERM
- std::cout << "!not computing metric!\n";
-#endif
- continue;
- }
-// metrics are close enough; do the computation and the compare
-// get the output bits for this connection
- float* t_output_bit = t_connection->d_output_bits;
- if (d_do_mux_inputs == true) {
-// if using mux'ed input streams, handle differently
- const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
-// loop over all encoder-output values
- for (size_t r = d_n_code_outputs; r > 0; r--) {
- t_metric += ((*t_in_buf++) * (*t_output_bit++));
- }
- } else {
-// loop over all encoder-output values
- for (size_t r = 0; r < d_n_code_outputs; r++) {
- t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
- }
- }
-// done with this input value; compare old and new metrics
-// see if it's the best metric
- if (t_metric > t_to_metric) {
-#if DO_PRINT_DEBUG_TERM
- std::cout << "New Metric to s[" <<
- n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
- if (t_to_state->d_max_metric == -1e10) {
- std::cout << "setting to ";
- } else {
- std::cout << "was s[" <<
- n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
- "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
- "]@ " << t_to_state->d_max_metric << " now ";
- }
- std::cout << "s[" << n2bs(t_state_ndx,t_state_print_bits) <<
- "] i[" << n2bs (0, d_n_code_inputs+1) << "]@ " << t_metric <<
"\n";
-#endif
- t_to_state->d_max_metric = t_metric;
- t_to_state->d_max_state_ndx = t_state_ndx;
- t_to_state->d_max_input = 0;
- }
-// add the "to" state's index to the "next" set of state's indices list
- *t_next_state_ndx_ptr++ = t_connection->d_to_ndx;
-// finished (for) this state
- }
-// done with all states and all inputs; now update the traceback structure
-// change which d_states' index to use as starting
- d_states_ndx ^= 1;
-// update the number of "up_term" states
- d_up_term_ndx ^= 1;
-// reduce the number of using states
- t_n_up_down_ndx >>= d_n_code_inputs;
-// reset the state's index for each set of new inputs
- t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
-// update the traceback structure
-// loop over all current states
- traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
- traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
-#if DO_PRINT_DEBUG_TERM_1
- std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
-#endif
-// loop over all current stored "term" state indices
- for (size_t n = 0; n < t_n_up_down_ndx; n++) {
-// get the start index and then pointer to each of the "to" states,
-// which hold the newest "max" stuff
- size_t t_state_ndx = *t_state_ndx_ptr++;
- state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
-// simple: get the current state & output state
-// and connect output to the current, set inputs on output
- traceback_t_ptr t_out_buf = &(t_out_bufs[t_state_ndx]);
- traceback_t_ptr t_prev_out_buf =
- &(t_prev_out_bufs[t_state->d_max_state_ndx]);
-#if DO_PRINT_DEBUG_TERM_1
- std::cout << "ndx[" << n << "] == " << t_state_ndx <<
- ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
- "]: max_ndx = " <<
- n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
- ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
- ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
-#endif
- t_out_buf->d_prev = t_prev_out_buf;
- t_out_buf->d_inputs = t_state->d_max_input;
-// finished (for) this state
- }
-// increment the in_buf index, depending on mux'ing or not
- t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
-// increment the time counters
- t_time_count--;
- d_time_count++;
-// finished (while) staying in this fsm state or not
- }
- if (t_time_count == 0) {
-// finished this trellis, now move as much of the decoded input to the
-// output buffer as possible
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Setting FSM to fsm_dec_output\n";
-#endif
- d_fsm = fsm_dec_output;
- }
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Exited fsm_dec_doing_term\n";
-#endif
- break;
- case (fsm_dec_output):
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Entered fsm_dec_output.\n";
-#endif
-// this is done in reverse bit order (last time to first time)
-// using the traceback structure in d_out_buf, starting with
-// the maximum valued one in the last time slot, then using
-// the traceback's "d_prev" link to trace the trellis back
-
-// see where the output data will terminate
- int t_next_out_buf_ndx = (t_out_buf_ndx +
- (d_frame_size_bits / g_num_bits_per_byte));
- int t_next_out_bit_shift = (t_out_bit_shift +
- (d_frame_size_bits % g_num_bits_per_byte));
- if (t_next_out_bit_shift >= g_num_bits_per_byte) {
- t_next_out_bit_shift -= g_num_bits_per_byte;
- t_next_out_buf_ndx++;
- }
-#if DO_PRINT_DEBUG_OUTPUT
- std::cout << "First bit in at out[][" << t_out_buf_ndx << "].[" <<
- t_out_bit_shift << "] -> " << d_frame_size_bits << " bits == " <<
- (d_frame_size_bits / g_num_bits_per_byte) << " Byte" <<
- ((d_frame_size_bits / g_num_bits_per_byte) != 1 ? "s" : "") <<
- " + " << (d_frame_size_bits % g_num_bits_per_byte) << " bit" <<
- ((d_frame_size_bits % g_num_bits_per_byte) != 1 ? "s" : "") <<
- "\nNext set of bits start at out[][" << t_next_out_buf_ndx <<
- "].[" << t_next_out_bit_shift << "]\n";
-#endif
-// find the starting traceback structure
- traceback_t_ptr t_out_buf;
- if (d_do_termination == true) {
-// FIXME: assume termination state == 0
-#if DO_PRINT_DEBUG_OUTPUT_0
- std::cout << "Using termination; going through trellis for " <<
- d_max_memory << " bit" <<
- ((d_max_memory != 1) ? "s" : "") << "\n";
-#endif
- t_out_buf = &(d_out_buf[d_time_count][0]);
-#if DO_PRINT_DEBUG_OUTPUT_0
- std::cout << "Starting traceback ptr " << t_out_buf << "\n";
-#endif
-// skip over the termination bits
- for (size_t n = d_max_memory; n > 0; n--) {
- t_out_buf = t_out_buf->d_prev;
-#if DO_PRINT_DEBUG_OUTPUT_0
- std::cout << "Next traceback ptr " << t_out_buf << "\n";
-#endif
- }
- } else {
-// no termination but doing block coding;
-// FIXME: use the state with the bext metric
-// get the state's index for each set of new inputs
- state_t_ptr t_state = d_states[d_states_ndx];
- float t_max_metric = t_state->d_max_metric;
- size_t t_max_state_ndx = 0;
- t_state++;
-// loop over all current states
- for (size_t n = 1; n < d_n_states; n++, t_state++) {
-// start with this state's metric
- float t_metric = t_state->d_max_metric;
-// compare with current max
- if (t_metric > t_max_metric) {
- t_max_metric = t_metric;
- t_max_state_ndx = n;
- }
- }
-// get the correct out_buf reference to start with
- t_out_buf = &(d_out_buf[d_time_count][t_max_state_ndx]);
- }
-#if DO_PRINT_DEBUG_OUTPUT
- std::cout << "Found starting traceback ptr " << t_out_buf <<
- "; getting all " << d_frame_size_bits << " bits per stream.\n";
-#endif
-// now we've got the starting traceback structure address;
-// check to make sure there is enough space in each output buffer
- size_t t_frame_bit_ndx = d_frame_size_bits;
- if ((t_next_out_buf_ndx > t_noutput_bytes) |
- ((t_next_out_buf_ndx == t_noutput_bytes) &
- (t_next_out_bit_shift != 0))) {
-// not enough space for all output bits;
-// find the number of extra bits to save
- size_t t_save_buf_ndx = t_next_out_buf_ndx - t_noutput_bytes;
- size_t t_n_extra_bits = ((t_save_buf_ndx * g_num_bits_per_byte) +
- t_next_out_bit_shift);
-// set the number of saved bits
- d_n_saved_bits = t_n_extra_bits;
-// remove the extra bits from the number to copy to the output buffer
- t_frame_bit_ndx -= t_n_extra_bits;
-// find the actual output buf index, once we get there
- t_next_out_buf_ndx -= t_save_buf_ndx;
-#if DO_PRINT_DEBUG_OUTPUT
- std::cout << "Not enough output buffer space:\n" <<
- "len (o_b) = " << t_noutput_bytes << " ==> " <<
- t_n_extra_bits << " extra bit" <<
- (t_n_extra_bits != 1 ? "s" : "") << " == " <<
- t_save_buf_ndx << " Byte" <<
- (t_save_buf_ndx != 1 ? "s" : "") << ", " <<
- t_next_out_bit_shift << " bit" <<
- (t_next_out_bit_shift != 1 ? "s" : "") << "\n";
-#endif
-// zero each output buffers' bytes
- size_t t_n_zero = t_save_buf_ndx + (t_next_out_bit_shift ? 1 : 0);
-#if DO_PRINT_DEBUG_OUTPUT
- size_t t_n_out_bytes = ((d_frame_size_bits / g_num_bits_per_byte) +
- ((d_frame_size_bits % g_num_bits_per_byte) ? 1
: 0));
- std::cout << "Zeroing save buffer from for " << t_n_zero <<
- " Byte" << (t_n_zero != 1 ? "s" : "") << " (of " <<
- d_frame_size_bits << " bit" <<
- (d_frame_size_bits != 1 ? "s" : "") << " == " << t_n_out_bytes <<
- " Byte" << (t_n_out_bytes != 1 ? "s" : "") << ")\n";
-#endif
- for (size_t m = 0; m < d_n_code_inputs; m++)
- bzero (d_save_buffer[m], t_n_zero);
-// loop over all extra bits
- for (size_t n = t_n_extra_bits; n > 0; n--) {
-// first decrement the output bit & byte as necessary
- if (--t_next_out_bit_shift < 0) {
- t_next_out_bit_shift += g_num_bits_per_byte;
- t_save_buf_ndx--;
- }
-// get the encoder inputs to output
- size_t t_inputs = t_out_buf->d_inputs;
-// loop over all code inputs (decoder-outputs), 1 bit per stream
- for (size_t m = 0; m < d_n_code_inputs; m++) {
- d_save_buffer[m][t_save_buf_ndx] |=
- ((t_inputs & 1) << t_next_out_bit_shift);
- t_inputs >>= 1;
- }
- t_out_buf = t_out_buf->d_prev;
-#if DO_PRINT_DEBUG_OUTPUT_0
- std::cout << "Next traceback ptr " << t_out_buf << "\n";
-#endif
- }
-// at exit, "t_out_buf_ndx" should be == t_noutput_bytes, and
-// "t_out_bit_shift" should be 0; check these!
-#if DO_PRINT_DEBUG_OUTPUT
- std::cout << "n_o_b_ndx (" << t_next_out_buf_ndx << ") ?=? " <<
- "#o_B (" << t_noutput_bytes << ") & t_o_b_sh (" <<
- t_next_out_bit_shift << ") ?=? 0\n";
- assert (t_next_out_buf_ndx == t_noutput_bytes);
- assert (t_next_out_bit_shift == 0);
-#endif
- }
-// set the correct output buffer index and bit shift
- t_out_bit_shift = t_next_out_bit_shift;
- t_out_buf_ndx = t_next_out_buf_ndx;
-// copy any remaining bits looping backwards in bit-time
-// through the traceback trellis
- for (size_t n = t_frame_bit_ndx; n > 0; n--) {
-// first decrement the output bit & byte as necessary
- if (--t_out_bit_shift < 0) {
- t_out_bit_shift += g_num_bits_per_byte;
- t_out_buf_ndx--;
- }
-// get the encoder inputs to output
- size_t t_inputs = t_out_buf->d_inputs;
-// loop over all code inputs (decoder-outputs), 1 bit per stream
- for (size_t m = 0; m < d_n_code_inputs; m++) {
- out_buf[m][t_out_buf_ndx] |= ((t_inputs & 1) << t_out_bit_shift);
- t_inputs >>= 1;
- }
- t_out_buf = t_out_buf->d_prev;
-#if DO_PRINT_DEBUG_OUTPUT_0
- std::cout << "Next traceback ptr " << t_out_buf << "\n";
-#endif
- }
-// set the next output byte and bit-shift
- t_out_bit_shift = t_next_out_bit_shift;
- t_out_buf_ndx = t_next_out_buf_ndx;
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Set FSM to fsm_dec_init\n";
-#endif
- d_fsm = fsm_dec_init;
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Exited fsm_dec_output\n";
-#endif
- break;
- case (fsm_dec_init):
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Entered fsm_dec_init\n";
-#endif
-// this is called immediately (first input bit upon startup),
-// or after termination of a trellis.
-
-// reset states to the 0'th one
- d_up_term_ndx = d_states_ndx = 0;
-// zero the metrics for those states
- zero_metrics (0);
-#if 0
-// might not need to do this; check and see after it works
-// reset up_term states and number so that there is 1 item, the "0" state.
- bzero (d_up_term_states_ndx[0], sizeof (size_t) * d_n_states);
- bzero (d_up_term_states_ndx[1], sizeof (size_t) * d_n_states);
-#else
- d_up_term_states_ndx[0][0] = 0;
-#endif
-// reset time count back to the start
- d_time_count = 0;
-#if 0
-// reset the traceback structures
-// might not need to do this; check and see after it works
- traceback_t_hdl t_out_bufs = d_out_buf;
- for (size_t n = d_n_traceback_els; n > 0; n--) {
- traceback_t_ptr t_out_buf = (*t_out_bufs++);
- for (size_t m = d_n_states; m > 0; m--, t_out_buf++) {
- t_out_buf->d_prev = NULL;
- t_out_buf->d_inputs = -1;
- }
- }
-#endif
-// set the fsm to "doing up"
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Set FSM to fsm_dec_doing_up\n";
-#endif
- d_fsm = fsm_dec_doing_up;
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Exited fsm_dec_init\n";
-#endif
- break;
-// should never get here!
- default:
- assert (0);
-// done (switch) with FSM
- }
-// done (while) there are inputs
- }
-
-// consume all of the input items on all input streams
-// "ninput_items[]" doesn't seem to be reliable,
-// so compute this from the actual number of frames processed
-#if DO_PRINT_DEBUG_EXIT
- std::cout << "Exiting FSM in state: " <<
- (d_fsm == fsm_dec_init ? "init" :
- (d_fsm == fsm_dec_doing_up ? "up" :
- (d_fsm == fsm_dec_doing_middle ? "middle" :
- (d_fsm == fsm_dec_doing_term ? "term" :
- (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "\n" <<
- "Consuming " << t_in_buf_ndx <<
- " input items on each input stream (of " << t_ninput_items << ").\n";
-#endif
- consume_each (t_in_buf_ndx);
-
-// make sure the number of output items makes sense
-// t_out_buf_ndx always points to the current index
-// t_out_bit_shift always points to the next bit position to be written
- int t_leftover_bytes = t_out_buf_ndx % d_out_stream_el_size_bytes;
- int t_leftover_bits = ((t_leftover_bytes * g_num_bits_per_byte) +
- t_out_bit_shift);
- int t_noutput_items = noutput_items;
-#if DO_PRINT_DEBUG_EXIT
- std::cout << "Final o_b[" << t_out_buf_ndx << "][" <<
- t_out_bit_shift << "] of " << t_noutput_bytes <<
- ", el_size = " << d_out_stream_el_size_bytes <<
- ", lo_Bytes = " << t_leftover_bytes <<
- ", t_lo_bits = " << t_leftover_bits << "\n" <<
- "Desired # output items = " << noutput_items << "\n";
-#endif
- if (t_leftover_bits != 0) {
- // should never get here!
-#if 1
- assert (0);
-#else
- int t_ndx = t_out_buf_ndx - t_leftover_bytes;
- size_t t_n_copy = t_leftover_bytes + ((t_out_bit_shift != 0) ? 1 : 0);
- assert (t_n_copy <= d_out_stream_el_size_bytes);
-// copy the leftover into the save buffer
- for (size_t n = 0; n < d_n_code_inputs; n++) {
- bcopy (&(out_buf[n][t_ndx]), d_save_buffer[n], t_n_copy);
- }
- t_noutput_items = t_ndx / d_out_stream_el_size_bytes;
- d_n_saved_bits = t_leftover_bits;
-#if DO_PRINT_DEBUG_EXIT
- std::cout << "Copied " << t_n_copy << " Byte" <<
- (t_n_copy != 1 ? "s" : "") << " from o_b[][" << t_ndx <<
- "] into each save buffer.\n" <<
- "Actual #output items = " << t_noutput_items <<
- ", # saved bit(s) = " << d_n_saved_bits << "\n";
-#endif
-#endif
- }
-
-#if DO_TIME_THOUGHPUT
- u_long d_t = end_timer (&t_tp);
-
- std::cout << "dec_blk_conv_soft_full: Completed " << t_ninput_items <<
- " bits in " << d_t << " usec => " <<
- 1e6*(((double)(t_ninput_items))/((double) d_t)) <<
- " b/s\n";
-#endif
-
-// returns number of items written to each output stream
- return (t_noutput_items);
-}
Index: gr_decoder_viterbi_block_soft_full.h
===================================================================
RCS file: gr_decoder_viterbi_block_soft_full.h
diff -N gr_decoder_viterbi_block_soft_full.h
--- gr_decoder_viterbi_block_soft_full.h 3 Jul 2006 02:12:53 -0000
1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,238 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio.
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef INCLUDED_GR_DECODER_VITERBI_BLOCK_SOFT_FULL_H
-#define INCLUDED_GR_DECODER_VITERBI_BLOCK_SOFT_FULL_H
-
-#include <gr_block.h>
-#include <vector>
-#include <sys/types.h>
-
-struct state_t;
-
-/*
- * connection_t: describes an output connection from the current
- * time-bit memory state to the next time-bit memory state
- *
- * d_to: state pointer to which this connection going
- *
- * d_to_ndx: index of the "to" state
- *
- * d_output_bits: what are the output bits, coverted into
- * 1->+1.0, 0->-1.0, for this connection
- */
-
-typedef struct connection_t {
- struct state_t *d_to;
- int d_to_ndx;
- float* d_output_bits;
-} connection_t, *connection_t_ptr;
-
-/*
- * state_t: describes a given memory state
- *
- * d_connections: a pointer to an array of these structures
- * will be used to describes a given time-bit's memory state;
- * an entry will be referenced via "state_add_to", to find the
- * connections to the next time-bit memory states. There is
- * one entry per each input bit combination -> 2^#I connections in all.
- * e.g. [0] means the all 0 input;
- * [1] means that input #1 was 1 while all the others were 0;
- * [2] means that input #2 was 1, while all the others were 0;
- * [3] means that inputs #1 and #2 were 1, while the others were 0.
- *
- * d_max_metric: the maximum metric thus far for this state
- *
- * d_max_state: the state from which the maximum metric was attained
- *
- * d_max_input: the input bits from which the maximum metric was attained
- */
-
-typedef struct state_t {
- connection_t_ptr d_connections;
- float d_max_metric;
- int d_max_state_ndx;
- int d_max_input;
-} state_t, *state_t_ptr;
-
-/*
- * state_get_from(v,i,k): use to retrieve a given bit-memory state,
- * from the inputs:
- *
- * int v: the value from which to retrieve the given state
- * int i: for which input stream (0 to #I-1)
- * int k: the number of memory slots per input (e.g. 1+D^2 -> 2)
- */
-
-#define state_get_from(v,i,k) (((v)>>((i)*(k)))&((1<<(k))-1))
-
-/*
- * state_add_to(s,i,v,k): use to create a given bit-memory state,
- * from the inputs:
- *
- * int s: the state value to modify
- * int i: for which input stream (0 to #I-1)
- * int v: value to set the state to for this input
- * int k: the number of memory slots per input (e.g. 1+D^2 -> 2)
- */
-
-#define state_add_to(s,v,i,k) (s)|=(((v)&((1<<(k))-1))<<((i)*(k)))
-
-/*
- * fsm_dec_t: finite state machine for the decoder
- *
- * fsm_dec_init: initialize for a new frame / block; this is already
- * done at instantiation, so do it only at the end of a block.
- *
- * fsm_dec_doing_up: starting the trellis; done for all types
- *
- * fsm_dec_doing_middle: full trellis; done for all types
- *
- * fsm_dec_doing_term: termination trellis, if requested
- *
- * fsm_dec_doing_output: output all bits
- */
-
-typedef enum {
- fsm_dec_init, fsm_dec_doing_up, fsm_dec_doing_middle,
- fsm_dec_doing_term, fsm_dec_output
-} fsm_dec_t;
-
-/*
- * traceback_t: used to store all encode-input bits for
- * all possible paths, when computing all trellis bits before
- * determining the ML decode-output sequence.
- *
- * d_prev: the connection to the previous bit's traceback structure
- *
- * d_inputs: the inputs (one per bit) for this connection
- */
-
-typedef struct traceback_t {
- struct traceback_t *d_prev;
- int d_inputs;
-} traceback_t, *traceback_t_ptr, **traceback_t_hdl;
-
-// GR stuff
-
-class gr_decoder_viterbi_block_soft_full;
-typedef boost::shared_ptr<gr_decoder_viterbi_block_soft_full>
-gr_decoder_viterbi_block_soft_full_sptr;
-
-gr_decoder_viterbi_block_soft_full_sptr gr_make_dec_blk_conv_soft_full
-(int frame_size_bits,
- int num_input_streams,
- int num_output_streams,
- std::vector<int> code_generator,
- bool do_termination);
-
-/*!
- * \brief Decode the incoming streams using a Viterbi-style decoder
- *
- * input: encoded data as soft symbols, either as individual
- * streams or mux'ed into 1 stream.
- *
- * output: stream(s) of user-defined element size.
- */
-
-class gr_decoder_viterbi_block_soft_full : public gr_block
-{
- friend gr_decoder_viterbi_block_soft_full_sptr
- gr_make_dec_blk_conv_soft_full (int frame_size_bits,
- int num_input_streams,
- int num_output_streams,
- std::vector<int> code_generator,
- bool do_termination);
-/*
- * frame_size_bits: if == 0, then do streaming decoding (infinite
- * trellis); otherwise this is the block size to decode before
- * terminating the trellis.
- *
- * code_generator: vector of integers (32 bit) representing the code
- * to be implemented in octal form. E.g. "04" in binary is "100",
- * which would be "D^2" for code generation. "06" == 110b == "D^2 + D"
- * ==> The vector is listed in order for each input stream, so if there
- * are 2 input streams (I1, I2) [specified in "n_code_inputs"]
- * and 2 output streams (O1, O2) [specified in "n_code_outputs"],
- * then the vector would be the code generator for:
- * [I1->O1, I1->O2, I2->O1, I2->O2]
- * with each element being the octal representation of the code.
- *
- * do_termination is valid only if frame_size_bits != 0, and defines
- * whether or not to to trellis termination.
- *
- * do_mux_input: is true, then the one input stream will be
- * interpreted as the multiplexing all of the input bits. For
- * example for a 3 input decoder, the input stream would be
- * [I1[k], I2[k], I3[k], I1[k+1], I2[k+1], ...], where "k" is the
- * input sample time, and "I1" through "I3" are the 3 input
- * streams.
- *
- * n_code_inputs: the number of decoder-input (encoder-output)
- * streams, no matter if separate or mux'ed
- *
- * n_code_outputs: the number of decoder-output (encoder-input) streams
- */
-
- gr_decoder_viterbi_block_soft_full (int frame_size_bits,
- int num_input_streams,
- int num_output_streams,
- std::vector<int> code_generator,
- bool do_termination);
-
-public:
- ~gr_decoder_viterbi_block_soft_full ();
-
- virtual void forecast (int noutput_items,
- gr_vector_int &ninput_items_required);
-
- virtual int general_work (int noutput_items,
- gr_vector_int &ninput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items);
-
- virtual int fixed_rate_noutput_to_ninput (int noutput_items);
-
-private:
- void reset_metrics (u_char which);
- void zero_metrics (u_char which);
-
-/*
- * d_n_total_input_bits_per_stream: how many bits to store for each
- * state to determine the best decoder-output (encoder-input) bits
- */
- size_t d_frame_size_bits;
- size_t d_n_code_outputs, d_n_code_inputs, d_max_memory;
- size_t d_time_count, d_n_total_input_bits_per_stream;
- size_t d_n_saved_bits, d_n_saved_bits_start_ndx, d_n_traceback_els;
- size_t d_n_states, d_n_input_combinations;
- size_t d_states_ndx, d_up_term_ndx;
- bool d_do_streaming, d_do_termination, d_do_mux_inputs;
- char **d_save_buffer;
- std::vector<int> d_code_generators;
- state_t_ptr d_states[2];
- fsm_dec_t d_fsm;
- size_t* d_up_term_states_ndx[2];
- traceback_t_hdl d_out_buf;
-};
-
-#endif /* INCLUDED_GR_DECODER_VITERBI_BLOCK_SOFT_FULL_H */
Index: gr_decoder_viterbi_block_soft_full.i
===================================================================
RCS file: gr_decoder_viterbi_block_soft_full.i
diff -N gr_decoder_viterbi_block_soft_full.i
--- gr_decoder_viterbi_block_soft_full.i 3 Jul 2006 02:12:53 -0000
1.1
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,39 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-GR_SWIG_BLOCK_MAGIC(gr,dec_blk_conv_soft_full);
-
-gr_decoder_viterbi_block_soft_full_sptr
-gr_make_decoder_viterbi_block_soft_full (int frame_size_bits,
- int num_input_streams,
- int num_output_streams,
- std::vector<int> code_generator,
- bool do_termination);
-
-class gr_decoder_viterbi_block_soft_full : public gr_block
-{
- gr_decoder_viterbi_block_soft_full (int frame_size_bits,
- int num_input_streams,
- int num_output_streams,
- std::vector<int> code_generator,
- bool do_termination);
-};
Index: libecc/decoder_viterbi_base.h
===================================================================
RCS file: libecc/decoder_viterbi_base.h
diff -N libecc/decoder_viterbi_base.h
--- libecc/decoder_viterbi_base.h 4 Jul 2006 20:57:32 -0000 1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,139 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef INCLUDED_DECODER_VITERBI_H
-#define INCLUDED_DECODER_VITERBI_H
-
-#include <vector>
-#include "decoder.h"
-
-/*!
- * \brief Decode the incoming metrics streams using the Viterbi algorithm.
- *
- * input: streams of metrics,
- *
- * output: streams of char, one stream per output as defined by the
- * instantiated code, using only the right-most justified bit as
- * the single output bit per output item.
- */
-
-class decoder_viterbi : public decoder
-{
-public:
-/*
- * frame_size_bits: if == 0, then do streaming encoding ("infinite"
- * trellis); otherwise this is the frame size in bits to decode
- * before terminating the trellis. This value -does not- include
- * any termination bits.
- *
- * n_code_inputs:
- * n_code_outputs:
- * code_generator: vector of integers (32 bit) representing the code
- * to be implemented in octal form. E.g. "04" in binary is "100",
- * which would be "D^2" for code generation. "06" == 110b == "D^2 + D"
- * ==> The vector is listed in order for each input stream, so if there
- * are 2 input streams (I1, I2) [specified in "n_code_inputs"]
- * and 2 output streams (O1, O2) [specified in "n_code_outputs"],
- * then the vector would be the code generator for:
- * [I1->O1, I1->O2, I2->O1, I2->O2]
- * with each element being the octal representation of the code.
- *
- * do_termination: valid only if frame_size_bits != 0, and defines
- * whether or not to use trellis termination. Default is to use
- * termination when doing block coding.
- *
- * start_memory_state: when starting a new block, the starting memory
- * state to begin encoding; there will be a helper function to
- * assist in creating this value for a given set of inputs;
- * default is the "all zero" state.
- *
- * end_memory_state: when terminating a block, the ending memory
- * state to stop encoding; there will be a helper function to
- * assist in creating this value for a given set of inputs;
- * default is the "all zero" state.
- */
-
- decoder_viterbi (int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- std::vector<int> &code_generators,
- int start_memory_state = 0,
- int end_memory_state = 0,
- bool do_termination = true,
- bool use_muxed_inputs = false,
- bool do_muxed_outputs = false,
- bool use_packed_input = false,
- bool do_packed_outputs = false);
-
- virtual ~decoder_viterbi () {};
-
- virtual size_t compute_n_input_bits (size_t n_output_bits);
- virtual size_t compute_n_output_bits (size_t n_input_bits);
- virtual size_t decode (const char** in_buf,
- char** out_buf,
- size_t n_bits_to_output);
- virtual size_t decode (const char** in_buf,
- size_t n_bits_to_input,
- char** out_buf);
-
-private:
-/*
- * fsm_dec_viterbi_t: finite state machine for the convolutional decoder;
- * output happens all the time, so that's built-in to each state.
- *
- * fsm_dec_viterbi_init: initialize for a new frame / block; this is already
- * done at instantiation, so do it only at the end of a block.
- *
- * fsm_dec_viterbi_doing_up: encoding at the start of a block
- *
- * fsm_dec_viterbi_doing_middle: doing encoding inside the trellis
- *
- * fsm_dec_viterbi_doing_term: termination trellis, if requested
- */
-
- enum fsm_dec_viterbi_t {
- fsm_dec_viterbi_init, fsm_dec_viterbi_doing_up,
- fsm_dec_viterbi_doing_middle, fsm_dec_viterbi_doing_term
- };
-
- virtual void decode_private (const char** in_buf, char** out_buf);
- virtual void decode_loop (const char** in_buf, char** out_buf,
- size_t* which_counter, size_t how_many);
- virtual char get_new_input_bit (const char** in_buf, size_t code_input_n);
- virtual char get_new_input_bit__up (const char** in_buf,
- size_t code_input_n);
- virtual char get_new_input_bit__middle (const char** in_buf,
- size_t code_input_n);
- virtual char get_new_input_bit__term (size_t code_input_n);
- virtual void output_bit (char t_out_bit, char** out_buf,
- size_t t_output_stream);
- virtual void increment_counters (bool while_encoding);
-
- fsm_dec_viterbi_t d_fsm_state;
- bool d_use_muxed_inputs, d_do_muxed_outputs;
- bool d_use_packed_input, d_do_packed_outputs;
- bool d_do_streaming, d_do_termination;
- std::vector<memory_t> d_code_generators;
- std::vector<memory_t> d_states, d_init_states, d_term_states;
-};
-
-#endif /* INCLUDED_DECODER_VITERBI_H */
Index: libecc/encoder_convolutional_base.cc
===================================================================
RCS file: libecc/encoder_convolutional_base.cc
diff -N libecc/encoder_convolutional_base.cc
--- libecc/encoder_convolutional_base.cc 4 Jul 2006 20:57:32 -0000
1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,730 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <encoder_convolutional_base.h>
-#include <assert.h>
-#include <iostream>
-
-#define DO_TIME_THOUGHPUT 1
-#define DO_PRINT_DEBUG 1
-
-#if DO_TIME_THOUGHPUT
-#include <mld/mld_timer.h>
-#endif
-#if DO_PRINT_DEBUG
-#include <mld/n2bs.h>
-#endif
-
-static const int g_max_frame_size_bits = 10000000;
-static const int g_max_num_streams = 10;
-
-void encoder_convolutional_base::encoder_convolutional_base_init
-(int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- std::vector<int> &code_generators,
- bool do_termination,
- int start_memory_state,
- int end_memory_state)
-{
- // do error checking on the input arguments
-
- // make sure the frame length makes sense
-
- if ((frame_size_bits < 0) | (frame_size_bits > g_max_frame_size_bits)) {
- std::cerr << "encoder_convolutional_base: " <<
- "Requested frame length (" << frame_size_bits <<
- " bits) must be between 0 and " << g_max_frame_size_bits <<
- " bits, with 0 being a streaming encoder.\n";
- assert (0);
- }
-
- // check to make sure the number of input streams makes sense
-
- if ((n_code_inputs <= 0) | (n_code_inputs > g_max_num_streams)) {
- std::cerr << "encoder_convolutional_base: " <<
- "Requested number of input streams (" <<
- n_code_inputs << ") must be between 1 and " <<
- g_max_num_streams << ".\n";
- assert (0);
- }
-
- // check to make sure the number of output streams makes sense
-
- if ((n_code_outputs <= 0) | (n_code_outputs > g_max_num_streams)) {
- std::cerr << "encoder_convolutional_base: " <<
- "Requested number of output streams (" <<
- n_code_outputs << ") must be between 1 and " <<
- g_max_num_streams << ".\n";
- assert (0);
- }
-
- // make sure the code_generator is the correct length
-
- if (code_generators.size () !=
- ((size_t)(n_code_inputs * n_code_outputs))) {
- std::cerr << "encoder_convolutional_base: " <<
- "Number of code generator entries (" << code_generators.size () <<
- ") is not equal to the product of the number of input and output" <<
- " streams (" << (n_code_inputs * n_code_outputs) << ").\n";
- assert (0);
- }
-
- // create the class frame variables
-
- d_frame_size_bits = frame_size_bits;
- d_n_code_inputs = n_code_inputs;
- d_n_code_outputs = n_code_outputs;
- d_do_streaming = (frame_size_bits == 0);
- d_do_termination = (d_do_streaming == true) ? false : do_termination;
-
- // allocate the vectors for doing the encoding. use memory_t (an
- // interger type, at least 32 bits) bits to represent memory and the
- // code, as it makes the operations quite simple the state vectors.
-
- // d_states is a "matrix" [#input by #outputs] containing pointers
- // to memory_t's; this is done to make feedback function properly,
- // and doesn't effect the computation time for feedforward. The
- // issue is that any code with the same feedback can use the same
- // memory - thus reducing the actual number of memories required.
- // These overlapping encoders will use the same actual memory, but
- // given that there is no way to know a-priori where they are, use
- // pointers over the full I/O matrix-space to make sure each I/O
- // encoder uses the correct memory.
- // reference the matrix using "maio(i,o)" ... see .h file.
-
- d_states.assign (d_n_code_inputs * d_n_code_outputs, NULL);
-
- // code generators (feedforward part) are [#inputs x #outputs],
- // always - one for each I/O combination.
- // reference the matrix using "maio(i,o)" ... see .h file
-
- d_code_generators.assign (d_n_code_inputs * d_n_code_outputs, 0);
-
- // for now, assign the feedback to the "1" for each code - meaning
- // no feedback. Set the variable for feedback to "false".
- // reference the matrix using "maio(i,o)" ... see .h file
-
- d_code_feedback.assign (d_n_code_inputs * d_n_code_outputs, 1);
- d_do_feedback = false;
-
- // check the input code_generator for correctness & find the memory order
- // t_max_mem will be the mamimum number of memories used by the generator
-
- size_t t_max_mem = 0;
-
- // loop over all input streams first, output streams second
-
- for (size_t n = 0; n < d_n_code_outputs; n++) {
- memory_t t_all_inputs_zero = 0;
- for (size_t m = 0; m < d_n_code_inputs; m++) {
- size_t t_in_code = d_code_generators[maio(m,n)] =
- code_generators[maio(m,n)];
-
- // check that not all codes for this input are 0
-
- t_all_inputs_zero |= t_in_code;
-
- // find the memory requirement for this code generator
-
- size_t t_code_mem = 0;
- while (t_in_code != 0) {
- t_in_code >>= 1;
- t_code_mem++;
- }
- if (t_code_mem > t_max_mem)
- t_max_mem = t_code_mem;
- }
-
- // check this input to make sure all encoders were not '0'
-
- if (t_all_inputs_zero == 0) {
- std::cerr << "encoder_convolutional_base: " <<
- "At least 1 generator code for output " << n+1 <<
- " must be non-0.\n";
- assert (0);
- }
- }
-
- // store the maximum memory order (e.g. "2" -> D^2)
-
- d_max_memory = t_max_mem - 1;
-
- // make sure the frame length makes sense, #2
-
- if ((d_frame_size_bits != 0) & (d_frame_size_bits < d_max_memory)) {
- std::cerr << "encoder_convolutional_base: " <<
- "Requested frame length (" << d_frame_size_bits <<
- " bit" << (d_frame_size_bits > 1 ? "s" : "") <<
- ") must be at least 1 memory length (" << d_max_memory <<
- " bit" << (d_max_memory > 1 ? "s" : "") <<
- " for this code) when doing block coding.\n";
- assert (0);
- }
-
- // create the memory mask for this code generator
-
- d_max_mem_mask = (2 << d_max_memory) - 1;
-
-// FIXME: STILL NEED TO parse START AND END MEMORY STATES;
-
- // set the initial FSM state to 'init'
-
- d_fsm_state = fsm_enc_conv_init;
-
- if (DO_PRINT_DEBUG) {
- std::cout << "Encoder:\n Mask = " <<
- n2bs (d_max_mem_mask, d_max_memory+2) <<
- "\n Max_Mem = " << d_max_memory << "\n.";
- }
-
- // by default no Feedback;
- // setup for that from here down:
- // 1 memory per input; same for init and term states;
-
- d_n_memories = d_n_code_inputs;
- d_memory.assign (d_n_code_inputs, 0);
- d_init_states.assign (d_n_code_inputs, 0);
- d_term_states.assign (d_n_code_inputs, 0);
-
- // assign input numbers, one per memory
-
- for (size_t n = 0; n < d_n_code_inputs; n++)
- d_input_num[n] = n;
-
- // assign d_states' pointers correctly
- // loop over all I/O streams
-
- for (size_t n = 0; n < d_n_code_outputs; n++)
- for (size_t m = 0; m < d_n_code_inputs; m++)
- d_states[maio(m,n)] = &(d_memory[m]);
-}
-
-encoder_convolutional_base::encoder_convolutional_base
-(int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- std::vector<int> &code_generators,
- std::vector<int> &code_feedback,
- bool do_termination,
- int start_memory_state,
- int end_memory_state)
-{
- // call the general init routine, to parse inputs; deal with
- // feedback after this parsing.
-
- encoder_convolutional_base_init
- (frame_size_bits,
- n_code_inputs,
- n_code_outputs,
- code_generators,
- do_termination,
- start_memory_state,
- end_memory_state);
-
- // need to check the code_feedback to make sure it's valid; need to
- // update the "d_max_memory" and comment back to the user if
- // feedback is longer than feedforward. Otherwise, everything else
- // is done by the super-class.
-
- d_do_feedback = true;
-
- // resize the memory and states to the max size, worst case
-
- d_memory.assign (d_n_code_inputs * d_n_code_outputs, 0);
- d_init_states.assign (d_n_code_inputs * d_n_code_outputs, 0);
- d_term_states.assign (d_n_code_inputs * d_n_code_outputs, 0);
- d_code_feedback.assign (d_n_code_inputs * d_n_code_outputs, 0);
- d_input_num.assign (d_n_code_inputs * d_n_code_outputs, 0);
-
- // check the code_feedback for correctness & find the memory order
- // t_max_mem will be the mamimum number of memories used by the
- // feedback; code_feedback will be in "input" first order, which is
- // what is required internally.
-
- size_t t_max_mem = d_n_memories = 0;
- memory_t t_all_inputs_one = 0;
-
- for (size_t n = 0; n < d_n_code_outputs; n++) {
- size_t t_n_unique_fb_prev_start = d_n_memories;
-
- for (size_t m = 0; m < d_n_code_inputs; m++) {
- size_t t_save_code = code_feedback[maio(m,n)];
- size_t t_in_code = t_save_code;
-
- // check to make sure (code & 1) == 1; can't do this type of
- // convolutional encoder without it!
-
- if ((t_in_code & 1) != 1) {
- std::cerr << "encoder_convolutional_base: " <<
- "All feedback codes must contain a '1' for the least "
- "significant bit.\n";
- assert (0);
- }
-
- // find if this feedback is unique for this input;
-
- size_t l_n_unique_fb = t_n_unique_fb_prev_start;
- while (l_n_unique_fb < d_n_memories) {
- if (d_code_feedback[l_n_unique_fb] == t_save_code)
- break;
- l_n_unique_fb++;
- }
- if (l_n_unique_fb == d_n_memories) {
-
- // this is a unique feedback;
- // create new entries for it in d_code_feedback and d_input_num
-
- d_code_feedback[l_n_unique_fb] = t_save_code;
- d_input_num[l_n_unique_fb] = m;
-
- // update the "or" of all unique memories
-
- t_all_inputs_one |= t_save_code;
-
- // find the memory requirement for this code feedback
-
- size_t t_code_mem = 0;
- t_in_code = t_save_code;
- while (t_in_code != 0) {
- t_in_code >>= 1;
- t_code_mem++;
- }
- if (t_code_mem > t_max_mem)
- t_max_mem = t_code_mem;
-
- // increase the number of unique feedback codes
-
- d_n_memories++;
- }
-
- // create the new entry in d_states
-
- d_states[maio(m,n)] = &(d_memory[l_n_unique_fb]);
- }
- }
-
- // check to see if all the feedback entries were "1", which implies
- // no feedback; warn the user in that case.
-
- if (t_all_inputs_one == 1) {
- std::cout << "encoder_convolutional_base: Warning: " <<
- "No feedback is required, use of the non-feedback constructor "
- "will provide higher throughput.\n";
- }
-
- // check to see if the feedback's memory requirements are greater
- // than the feedforward's; warn the user (not sure why, but it seems
- // like a good idea).
-
- if (--t_max_mem > d_max_memory) {
- std::cout << "encoder_convolutional_base: Warning: " <<
- "Feedback using more memory than feedforward.\n";
- d_max_memory = t_max_mem;
-
- // make sure the frame length makes sense, #2
-
- if ((d_do_streaming == true) & (d_frame_size_bits < d_max_memory)) {
- std::cerr << "encoder_convolutional_base: " <<
- "Requested frame length (" << d_frame_size_bits <<
- " bit" << (d_frame_size_bits > 1 ? "s" : "") <<
- ") must be at least 1 memory length (" << d_max_memory <<
- " bit" << (d_max_memory > 1 ? "s" : "") <<
- " for this code) when doing block coding.\n";
- assert (0);
- }
-
- // create the memory mask for this code generator
-
- d_max_mem_mask = (2 << d_max_memory) - 1;
- }
-}
-
-void
-encoder_convolutional_base::encode_private
-(const char** in_buf,
- char** out_buf)
-{
-#if DO_TIME_THOUGHPUT
- struct timeval t_tp;
- start_timer (&t_tp);
-#endif
-
- // reset buffer indices
-
- d_total_n_enc_bits = d_in_buf_ndx = d_out_buf_ndx =
- d_in_bit_shift = d_out_bit_shift = 0;
-
- if (DO_PRINT_DEBUG) {
- std::cout << "Beginning this encode() call; starting parameters.\n";
- std::cout << "d_n_input_bits_left = " << d_n_input_bits_left << '\n';
- std::cout << "d_n_output_bits_left = " << d_n_output_bits_left << '\n';
- }
-
- // while there are inputs and outputs left to process ...
-
- while ((d_n_input_bits_left != 0) & (d_n_output_bits_left != 0)) {
-
- // jump to the correct state in the fsm
-
- switch (d_fsm_state) {
-
- case fsm_enc_conv_init:
-
- // copy the init states to the current memory
-
- d_memory = d_init_states;
-
- // if not doing streaming, things to do; else nothing more do
-
- if (d_do_streaming == false) {
-
- // reset the number of encoded bits in this block (which is
- // used to compare with the number of bits in the frame)
-
- d_n_enc_bits = 0;
- }
-
- // move to the 'input' state
-
- d_fsm_state = fsm_enc_conv_doing_input;
- break;
-
- case fsm_enc_conv_doing_input:
-
- // working through the trellis section which requires input bits
- // from external sources; loop up to the frame size (before
- // termination bits, if any), counting down the number of
- // available input bits.
-
- encode_loop (in_buf, out_buf, &d_n_input_bits_left, d_frame_size_bits);
-
- // finished this loop; check for jumping to the next state
-
- if ((d_n_enc_bits == d_frame_size_bits) & (d_do_streaming == false)) {
-
- // jump to another state, depending on termination requirement
-
- if (d_do_termination == true) {
- d_n_enc_bits = 0;
- d_fsm_state = fsm_enc_conv_doing_term;
- } else {
- d_fsm_state = fsm_enc_conv_init;
- }
- }
- break;
-
- case fsm_enc_conv_doing_term:
-
- // terminating the trellis, trying to get to a specific state;
- // better get here only when do_termination is true, but check
- // just in case; lop up to the max memory, counting down the
- // number of output bits left
-
- if (d_do_termination == false) {
- encode_loop (in_buf, out_buf, &d_n_output_bits_left, d_max_memory);
-
- // finished this loop; check for jumping to the next state
-
- if (d_n_enc_bits == d_max_memory)
- d_fsm_state = fsm_enc_conv_init;
-
- } else {
- // should never get here!
- assert (0);
- }
- break;
-
- default:
- // better never get here!
- assert (0);
- break;
-
- // done (switch) with FSM
- }
-
- // done (while) there are inputs and outputs
- }
-
- if (DO_PRINT_DEBUG) {
- std::cout << "Done with this encode() call; ending parameters.\n"
- "d_in_bit_shift = " << d_in_bit_shift << "\n"
- "d_out_bit_shift = " << d_out_bit_shift << "\n"
- "d_in_buf_ndx = " << d_in_buf_ndx << "\n"
- "d_out_buf_ndx = " << d_out_buf_ndx << "\n"
- "d_n_input_bits_left = " << d_n_input_bits_left << "\n"
- "d_n_output_bits_left = " << d_n_output_bits_left << "\n"
- "d_total_n_enc_bits = " << d_total_n_enc_bits << "\n";
- }
-
- if (DO_TIME_THOUGHPUT) {
- // compute the throughput for this particular function call
- u_long d_t = end_timer (&t_tp);
- std::cout << "Completed " << d_total_n_enc_bits <<
- " bits in " << d_t << " usec => " <<
- 1e6*(((double) d_total_n_enc_bits)/((double) d_t)) <<
- " b/s\n";
- }
-}
-
-void
-encoder_convolutional_base::encode_loop
-(const char** in_buf,
- char** out_buf,
- size_t* which_counter,
- size_t how_many)
-{
- if (DO_PRINT_DEBUG) {
- std::cout << "starting encode_loop.\n";
- }
- while (((*which_counter) > 0) & (d_n_enc_bits < how_many)) {
- if (DO_PRINT_DEBUG) {
- std::cout << "*w_c = " << (*which_counter) << ", "
- "# enc_bits = " << d_n_enc_bits << " of " << how_many << ".\n"
- "Getting new inputs.\n";
- }
-
- // get a new input bit per stream, and update the memory;
- // loop over all inputs, push the current state bit into d_memory
- // (which is pointed to by d_states, and thus both are updated).
-
- for (size_t p = 0; p < d_n_memories; p++) {
- if (DO_PRINT_DEBUG) {
- std::cout << "mem_in[" << p << "] = " <<
- n2bs (d_memory[p], d_max_memory+2) << "\n";
- }
-
- d_memory[p] |= get_next_bit (in_buf, d_input_num[p]);
-
- if (DO_PRINT_DEBUG) {
- std::cout << "mem_out[" << p << "] = " <<
- n2bs (d_memory[p], d_max_memory+2) << "\n";
- }
- }
-
- // now encode those inputs using the code generators,
- // and output a single bit per output stream
-
- // loop over all outputs
-
- for (size_t q = 0; q < d_n_code_outputs; q++) {
- memory_t t_out_result = 0;
-
- // loop over all inputs, xor'ing the result each time
-
- for (size_t p = 0; p < d_n_code_inputs; p++) {
- memory_t t_c_g = d_code_generators[maio(p,q)];
- memory_t t_mem = (*(d_states[maio(p,q)]));
-
- if (DO_PRINT_DEBUG) {
- std::cout << "b_i = " <<
- n2bs (t_out_result, d_max_memory+2) <<
- ", st[" << p << "," << q << "] = " <<
- n2bs (t_mem, d_max_memory+2) <<
- ", cg[" << p << "," << q << "] = " <<
- n2bs (t_c_g, d_max_memory+2) <<
- ", st[] & cg[] = " <<
- n2bs (t_mem & t_c_g, d_max_memory+2);
- }
-
- t_out_result ^= (t_mem & t_c_g);
-
- if (DO_PRINT_DEBUG) {
- std::cout << ", b_o = " <<
- n2bs (t_out_result, d_max_memory+2) << '\n';
- }
- }
- if (DO_PRINT_DEBUG) {
- std::cout << "b_r = " << n2bs (t_out_result, d_max_memory+2);
- }
-
- // sum the number of set bits, mod 2, for the output bit
-
- char t_out_bit = sum_bits_mod2 (t_out_result, d_max_memory);
-
- if (DO_PRINT_DEBUG) {
- std::cout << "t_out_bit = mo2_sum (b_o) = " <<
- n2bs (t_out_result, 2);
- }
-
- // output this particular bit on this output stream
-
- output_bit (t_out_bit, out_buf, q);
-
- // increment the input and output indices, if necessary, between
- // output bits
-
- increment_io_indices (true);
- }
-
- // do post-encoding memory mods (e.g. feedback); at a minimum:
- // must shift memory to get ready for a new input bit, and mask
- // off any extra bit from shifting (beyond a particular input's
- // memory bits).
-
- update_memory_post_encode ();
-
- // increment the input and output counters, if necessary, between
- // input bits
-
- increment_io_indices (false);
-
- // increment the number of encoded bits for the current block, and
- // the total number of bits for this running of "encode()"
-
- d_n_enc_bits++;
- d_total_n_enc_bits++;
-
- // decrement the number of input and output bits left
-
- d_n_input_bits_left--;
- d_n_output_bits_left--;
- }
-
- if (DO_PRINT_DEBUG) {
- std::cout << "ending encode_loop.\n";
- }
-}
-
-void
-encoder_convolutional_base::update_memory_post_encode
-()
-{
- if (DO_PRINT_DEBUG) {
- std::cout << "starting update_memory_post_encode.\n";
- }
-
- // update memory with any feedback, then shift up (left) by 1 bit
- // and mask the memory state to be ready for the next input
-
- // loop over all memories, shift the memory left (up) by 1 bit and
- // mask off any high non-memory bit(s)
-
- if (DO_PRINT_DEBUG) {
- std::cout << " doing memory shift and mask:\n";
- }
-
- for (size_t p = 0; p < d_n_memories; p++) {
- if (DO_PRINT_DEBUG) {
- std::cout << " mem_in[" << p << "] = " <<
- n2bs (d_memory[p], d_max_memory+2) << "\n";
- }
-
- d_memory[p] = (d_memory[p] << 1) & d_max_mem_mask;
-
- if (DO_PRINT_DEBUG) {
- std::cout << " mem_out[" << p << "] = " <<
- n2bs (d_memory[p], d_max_memory+2) << "\n";
- }
- }
-
- if (d_do_feedback == true) {
-
- if (DO_PRINT_DEBUG) {
- std::cout << " doing feedback:\n";
- }
-
- // loop over all unique memories, creating the feedback bit for each
- // and placing those bits in the state's second bit location
-
- for (size_t p = 0; p < d_n_memories; p++) {
- if (DO_PRINT_DEBUG) {
- std::cout << " mem_in[" << p << "] = " <<
- n2bs (d_memory[p], d_max_memory+2) << "\n";
- }
-
- // do feedback with current memory
- // get the memory, and zero out the second bit
-
- memory_t t_state = d_memory[p] & (d_max_mem_mask ^ 2);
-
- if (DO_PRINT_DEBUG) {
- std::cout << " t_state = mem[] & (" << d_max_mem_mask <<
- " xor 2) = " << n2bs (t_state, d_max_memory+2) << "\n";
- }
-
- // create the code feedback state
-
- memory_t t_fb_state = t_state & (d_code_feedback[p]);
-
- if (DO_PRINT_DEBUG) {
- std::cout << " t_fb_state = t_state & {fb[" << p << "] == " <<
- d_code_feedback[p] << "} = " <<
- n2bs (t_fb_state, d_max_memory+2) << "\n";
- }
-
- // mod2 sum the feedback state to get the feedback bit value
-
- char t_fb_bit = sum_bits_mod2 (t_fb_state, d_max_memory);
-
- if (DO_PRINT_DEBUG) {
- std::cout << " t_fb_bit = mod2_sum (t_fb_state) = " <<
- n2bs (t_fb_bit, 2) << "\n";
- }
-
- // place the feedback bit into the second state bit
-
- d_memory[p] = t_state | (t_fb_bit << 1);
-
- if (DO_PRINT_DEBUG) {
- std::cout << " mem_out[" << p << "] = t_state | (fb_bit << 1) = " <<
- n2bs (d_memory[p], d_max_memory+2) << "\n";
- }
- }
- }
-
- if (DO_PRINT_DEBUG) {
- std::cout << "ending update_memory_post_encode.\n";
- }
-}
-
-char
-encoder_convolutional_base::get_next_bit
-(const char** in_buf,
- size_t code_input_n)
-{
- char ret_val = 0;
- switch (d_fsm_state) {
- case fsm_enc_conv_doing_input:
- ret_val = get_next_bit__input (in_buf, code_input_n);
- break;
- case fsm_enc_conv_doing_term:
- ret_val = get_next_bit__term (code_input_n);
- break;
- default:
- assert (0);
- break;
- }
- return (ret_val);
-}
-
-char
-encoder_convolutional_base::get_next_bit__term
-(size_t code_input_n)
-{
- // FIXME: how to figure out which term bit to get?
- return (d_term_states[code_input_n] & 1);
-}
Index: libecc/encoder_convolutional_base.h
===================================================================
RCS file: libecc/encoder_convolutional_base.h
diff -N libecc/encoder_convolutional_base.h
--- libecc/encoder_convolutional_base.h 4 Jul 2006 20:57:32 -0000 1.2
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,197 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef INCLUDED_ENCODER_CONVOLUTIONAL_BASE_H
-#define INCLUDED_ENCODER_CONVOLUTIONAL_BASE_H
-
-#include <vector>
-#include "encoder.h"
-
-class encoder_convolutional_base : public encoder
-{
-public:
-/*!
- * Class encoder_convolutional_base is derived from the general
- * encoder class.
- *
- * Encode the incoming streams using a convolutional encoder; This is
- * a virtual base class which defines the basics of a
- * convolutional encoder, but not how input and output bits are
- * handled, nor feedback in the encoder. These features are all
- * defined by overriding methods appropriately.
- *
- * frame_size_bits: if == 0, then do streaming encoding ("infinite"
- * trellis); otherwise this is the frame size in bits to encode
- * before terminating the trellis. This value -does not- include
- * any termination bits.
- *
- * n_code_inputs:
- * n_code_outputs:
- * code_generator: vector of integers (32 bit) representing the code
- * to be implemented. E.g. "4" in binary is "100", which would be
- * "D^2" for code generation. "6" == 110b == "D^2 + D"
- * ==> The vector is listed in order for each output stream, so if there
- * are 2 input streams (I1, I2) [specified in "n_code_inputs"]
- * and 2 output streams (O1, O2) [specified in "n_code_outputs"],
- * then the vector would be the code generator for:
- * [I1->O1, I2->O1, I1->O2, I2->O2]
- * with each element being an integer representation of the code.
- *
- * do_termination: valid only if frame_size_bits != 0, and defines
- * whether or not to use trellis termination. Default is to use
- * termination when doing block coding.
- *
- * start_memory_state: when starting a new block, the starting memory
- * state to begin encoding; there will be a helper function to
- * assist in creating this value for a given set of inputs;
- * default is the "all zero" state.
- *
- * end_memory_state: when terminating a block, the ending memory
- * state to stop encoding; there will be a helper function to
- * assist in creating this value for a given set of inputs;
- * default is the "all zero" state.
- */
-
- inline encoder_convolutional_base (int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- std::vector<int> &code_generators,
- bool do_termination = true,
- int start_memory_state = 0,
- int end_memory_state = 0)
- {encoder_convolutional_base_init (frame_size_bits,
- n_code_inputs,
- n_code_outputs,
- code_generators,
- do_termination,
- start_memory_state,
- end_memory_state);};
-
-/*
- * Base encoder with feedback.
- *
- * code_feedback: vector of integers (32 bit) representing the code
- * feedback to be implemented (same as for the
- * code_generator). For this feedback type, the LSB ("& 1") must
- * be equal to 1 ... the represents the input bit for the given
- * encoder, without which there would be no encoding! Each
- * successive higher-order bit represents the output of that
- * delay block; for example "6" == 110b == "D^2 + D" means use
- * the current input bit + the output of the second delay block.
- * Listing order is the same as for the code_generator.
- */
-
- encoder_convolutional_base (int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- std::vector<int> &code_generators,
- std::vector<int> &code_feedback,
- bool do_termination = true,
- int start_memory_state = 0,
- int end_memory_state = 0);
-
- virtual ~encoder_convolutional_base () {};
-
-protected:
-/*
- * fsm_enc_conv_t: finite state machine for the convolutional encoder;
- * output happens all the time, so that's built-in to each state.
- *
- * fsm_enc_conv_init: initialize for a new frame / block; this is already
- * done at instantiation, so do it only at the end of a block.
- *
- * fsm_enc_conv_doing_input: doing encoding inside the trellis
- *
- * fsm_enc_conv_doing_term: termination trellis, if requested
- */
-
- enum fsm_enc_conv_t {
- fsm_enc_conv_init, fsm_enc_conv_doing_input, fsm_enc_conv_doing_term
- };
-
-/*
- * maio(i,o): matrix access into a vector, knowing the # of code
- * outputs (from inside the class). References into a vector with
- * code inputs ordered by code output.
- *
- * 'i' is the first dimension - immediate memory order first - the code input
- * 'o' is the second dimension - slower memory order second - the code output
- *
- * returns ((o*n_code_outputs) + i)
- */
-
- inline size_t maio(size_t i, size_t o) {return ((o*d_n_code_outputs) + i);};
-
-/*
- * maoi(i,o): matrix access into a vector, knowing the # of code
- * inputs (from inside the class). References into a vector with
- * code outputs ordered by code input.
- *
- * 'o' is the first dimension - immediate memory order first - the code output
- * 'i' is the second dimension - slower memory order second - the code input
- *
- * returns ((i*n_code_inputs) + o)
- */
-
- inline size_t maoi(size_t i, size_t o) {return ((i*d_n_code_inputs) + o);};
-
- // methods defined in this class
-
- void encoder_convolutional_base_init (int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- std::vector<int> &code_generators,
- bool do_termination,
- int start_memory_state,
- int end_memory_state);
- virtual void encode_private (const char** in_buf, char** out_buf);
- virtual void encode_loop (const char** in_buf, char** out_buf,
- size_t* which_counter, size_t how_many);
- virtual char get_next_bit (const char** in_buf, size_t code_input_n);
- virtual char get_next_bit__term (size_t code_input_n);
- virtual void update_memory_post_encode ();
-
- // methods which are required by classes which inherit from this
- // one; primarily just the parts which deal with getting input bits
- // and writing output bits, changing the indices for those buffers.
-
- virtual char get_next_bit__input (const char** in_buf,
- size_t code_input_n) = 0;
- virtual void increment_io_indices (bool while_encoding) = 0;
-
- // variables
-
- fsm_enc_conv_t d_fsm_state;
- bool d_do_streaming, d_do_termination, d_do_feedback;
- size_t d_n_memories;
-
- // code generators and feedback are stored internally in "maXY(i,o)"
- // order this allows for looping over all a single output and
- // computing all input parts sequentially.
-
- std::vector<memory_t> d_code_generators, d_code_feedback;
- std::vector<memory_ptr_t> d_states;
- std::vector<memory_t> d_memory, d_init_states, d_term_states;
- std::vector<size_t> d_input_num;
-};
-
-#endif /* INCLUDED_ENCODER_CONVOLUTIONAL_BASE_H */
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] gr-error-correcting-codes/src/lib Makefile.am e...,
Michael Dickens <=