[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r3362 - in gnuradio/branches/developers/michaelld/wip/
From: |
michaelld |
Subject: |
[Commit-gnuradio] r3362 - in gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src: lib lib/libecc lib/libecc/tests python |
Date: |
Mon, 21 Aug 2006 10:48:00 -0600 (MDT) |
Author: michaelld
Date: 2006-08-21 10:48:00 -0600 (Mon, 21 Aug 2006)
New Revision: 3362
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics_to_branches.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics_to_branches.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_syms_to_metrics.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_syms_to_metrics.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy_alt.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_standard.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_standard.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/doubly_linked_list.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_ecc.py
Removed:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/qa_ecc.py
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_test_coding_1.py
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_test_coding_2.py
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_test_encoder_convolutional_1.py
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_test_encoder_convolutional_2.py
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/Makefile.am
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.i
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.i
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/Makefile.am
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_io.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_types.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.h
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.cc
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/Makefile.am
Log:
WIP: First cut implementing the Lazy Viterbi decoder.
Removed non-standard python QA stuff; replaced with the generic test
for library loading.
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/Makefile.am
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/Makefile.am
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/Makefile.am
2006-08-21 16:48:00 UTC (rev 3362)
@@ -35,21 +35,21 @@
SWIGCPPPYTHONARGS = -fvirtual -python -modern $(PYTHON_CPPFLAGS) \
$(STD_DEFINES_AND_INCLUDES)
-ALL_IFILES = $(LOCAL_IFILES) $(NON_LOCAL_IFILES)
-
NON_LOCAL_IFILES = $(GNURADIO_I)
-LOCAL_IFILES = \
- ecc_syms_to_metrics.i \
- ecc_metrics_decode_viterbi_full_block.i \
- ecc_streams_encode_convolutional.i \
- ecc_streams_encode_turbo.i \
- ecc.i
+LOCAL_IFILES = \
+ $(top_srcdir)/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.i \
+
$(top_srcdir)/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.i
\
+
$(top_srcdir)/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.i
\
+
$(top_srcdir)/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.i
\
+ $(top_srcdir)/gr-error-correcting-codes/src/lib/ecc.i
# These files are built by SWIG. The first is the C++ glue.
# The second is the python wrapper that loads the _howto shared library
# and knows how to call our extensions.
+ALL_IFILES = $(LOCAL_IFILES) $(NON_LOCAL_IFILES)
+
BUILT_SOURCES = \
ecc.cc \
ecc.py
@@ -89,8 +89,8 @@
# These swig headers get installed in ${prefix}/include/gnuradio/swig
swiginclude_HEADERS = $(LOCAL_IFILES)
-ecc.cc ecc.py: ecc.i $(ALL_IFILES)
- $(SWIG) $(SWIGCPPPYTHONARGS) -module ecc -o ecc.cc $<
+ecc.cc ecc.py: $(top_srcdir)/gr-error-correcting-codes/src/lib/ecc.i
$(ALL_IFILES)
+ $(SWIG) $(SWIGCPPPYTHONARGS) -module ecc -o ecc.cc
$(top_srcdir)/gr-error-correcting-codes/src/lib/ecc.i
MOSTLYCLEANFILES = $(BUILT_SOURCES) *.pyc *.loT *~
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.cc
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -32,6 +32,9 @@
ecc_metrics_decode_viterbi_full_block_sptr
ecc_make_metrics_decode_viterbi_full_block
(int sample_precision,
+<<<<<<< .working
+ const ecc_streams_encode_convolutional_sptr& encoder)
+=======
int frame_size_bits,
int n_code_inputs,
int n_code_outputs,
@@ -39,19 +42,16 @@
bool do_termination,
int start_memory_state,
int end_memory_state)
+>>>>>>> .merge-right.r3343
{
return ecc_metrics_decode_viterbi_full_block_sptr
(new ecc_metrics_decode_viterbi_full_block
(sample_precision,
- frame_size_bits,
- n_code_inputs,
- n_code_outputs,
- code_generator,
- do_termination,
- start_memory_state,
- end_memory_state));
+ encoder));
}
+<<<<<<< .working
+=======
ecc_metrics_decode_viterbi_full_block_feedback_sptr
ecc_make_metrics_decode_viterbi_full_block_feedback
(int sample_precision,
@@ -127,25 +127,33 @@
setup_io_signatures (sample_precision, n_code_inputs, n_code_outputs);
}
+>>>>>>> .merge-right.r3343
ecc_metrics_decode_viterbi_full_block::~ecc_metrics_decode_viterbi_full_block
()
{
delete d_decoder;
d_decoder = 0;
- delete d_encoder;
- d_encoder = 0;
delete d_in_buf;
d_in_buf = 0;
delete d_out_buf;
d_out_buf = 0;
}
-void
-ecc_metrics_decode_viterbi_full_block::setup_io_signatures
+ecc_metrics_decode_viterbi_full_block::ecc_metrics_decode_viterbi_full_block
(int sample_precision,
- int n_code_inputs,
- int n_code_outputs)
+ const ecc_streams_encode_convolutional_sptr& encoder)
+ : gr_block ("metrics_decode_viterbi_full_block",
+ gr_make_io_signature (0, 0, 0),
+ gr_make_io_signature (0, 0, 0))
{
+ // error checking is done in the encoder and decoder classes
+ // so just use the parameters as given; will be correct!
+
+ // get the trellis
+
+ code_convolutional_trellis* l_trellis =
+ (code_convolutional_trellis*) encoder->encoder()->trellis ();
+
// create the decoder
//
// the input model: individual input streams; two per metric type
@@ -156,21 +164,18 @@
// individual output streams per decoded code input stream;
// each item is a 'char' type with 1 bit aligned on the LSB.
+ size_t n_code_inputs = l_trellis->n_code_inputs ();
+ size_t n_code_outputs = l_trellis->n_code_outputs ();
+
d_decoder = new decoder_viterbi_full_block (sample_precision,
- d_encoder);
+ l_trellis);
d_out_buf = new code_output_ic1l (n_code_inputs);
- // error checking is done in the encoder and decoder classes
- // so just use the parameters as given; will be correct!
-
- d_n_code_inputs = n_code_inputs;
- d_n_code_outputs = n_code_outputs;
-
// 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,
+ set_output_signature (gr_make_io_signature (n_code_inputs,
+ n_code_inputs,
sizeof (char)));
// determine the input signature element size
@@ -194,14 +199,14 @@
d_in_buf = new code_input_il (n_code_outputs);
}
- set_input_signature (gr_make_io_signature (2*d_n_code_outputs,
- 2*d_n_code_outputs,
+ set_input_signature (gr_make_io_signature (2*n_code_outputs,
+ 2*n_code_outputs,
l_input_item_size_bytes));
}
void ecc_metrics_decode_viterbi_full_block::forecast
(int noutput_items,
- gr_vector_int &ninput_items_required)
+ gr_vector_int& ninput_items_required)
{
int ninput_items = d_decoder->compute_n_input_items (noutput_items);
size_t ninputs = ninput_items_required.size();
@@ -212,14 +217,14 @@
int
ecc_metrics_decode_viterbi_full_block::general_work
(int noutput_items,
- gr_vector_int &ninput_items,
- gr_vector_const_void_star &input_items,
- gr_vector_void_star &output_items)
+ gr_vector_int& ninput_items,
+ gr_vector_const_void_star& input_items,
+ gr_vector_void_star& output_items)
{
// compute the actual number of output items (1 bit char's) created.
size_t t_n_input_items = d_decoder->compute_n_input_items (noutput_items);
-#if 1
+#if 0
size_t t_n_output_items = d_decoder->compute_n_output_bits (t_n_input_items);
assert (t_n_output_items == ((size_t)noutput_items));
#endif
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.h
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -23,19 +23,20 @@
#ifndef INCLUDED_ECC_METRICS_DECODE_VITERBI_FULL_BLOCK_H
#define INCLUDED_ECC_METRICS_DECODE_VITERBI_FULL_BLOCK_H
-#include <gr_block.h>
+#include <ecc_streams_encode_convolutional.h>
#include <libecc/decoder_viterbi_full_block.h>
-#include <libecc/encoder_convolutional.h>
class ecc_metrics_decode_viterbi_full_block;
typedef boost::shared_ptr<ecc_metrics_decode_viterbi_full_block>
-ecc_metrics_decode_viterbi_full_block_sptr,
-ecc_metrics_decode_viterbi_full_block_feedback_sptr;
+ecc_metrics_decode_viterbi_full_block_sptr;
ecc_metrics_decode_viterbi_full_block_sptr
ecc_make_metrics_decode_viterbi_full_block
(int sample_precision,
+<<<<<<< .working
+ const ecc_streams_encode_convolutional_sptr& encoder);
+=======
int frame_size_bits,
int n_code_inputs,
int n_code_outputs,
@@ -43,7 +44,10 @@
bool do_termination = true,
int start_memory_state = 0,
int end_memory_state = 0);
+>>>>>>> .merge-right.r3343
+<<<<<<< .working
+=======
ecc_metrics_decode_viterbi_full_block_feedback_sptr
ecc_make_metrics_decode_viterbi_full_block_feedback
(int sample_precision,
@@ -56,6 +60,7 @@
int start_memory_state = 0,
int end_memory_state = 0);
+>>>>>>> .merge-right.r3343
/*!
* \brief Decode the incoming streams using a Viterbi-style decoder,
* full trellis block decoding.
@@ -71,84 +76,25 @@
friend ecc_metrics_decode_viterbi_full_block_sptr
ecc_make_metrics_decode_viterbi_full_block
(int sample_precision,
- int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- const std::vector<int>& code_generator,
- bool do_termination,
- int start_memory_state,
- int end_memory_state);
+ const ecc_streams_encode_convolutional_sptr& encoder);
- friend ecc_metrics_decode_viterbi_full_block_feedback_sptr
- ecc_make_metrics_decode_viterbi_full_block_feedback
- (int sample_precision,
- int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- const std::vector<int>& code_generator,
- const std::vector<int>& code_feedback,
- bool do_termination,
- int start_memory_state,
- int end_memory_state);
/*
- * frame_size_bits: if == 0, then do streaming decoding (infinite
- * trellis); otherwise this is the block size to decode before
- * terminating the trellis.
+ * sample_precision: if == 0, then metrics are float precision and
+ * always in [0,1]; if in [1,32] (== M), then use M-ary integer
+ * precision and each metric will always be in [0,(2^M)-1].
*
- * 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
+ * encoder: the encoder which was used for the original data
*/
ecc_metrics_decode_viterbi_full_block
(int sample_precision,
- int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- const std::vector<int>& code_generator,
- bool do_termination,
- int start_memory_state,
- int end_memory_state);
+ const ecc_streams_encode_convolutional_sptr& encoder);
- ecc_metrics_decode_viterbi_full_block
- (int sample_precision,
- int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- const std::vector<int>& code_generator,
- const std::vector<int>& code_feedback,
- bool do_termination,
- int start_memory_state,
- int end_memory_state);
-
void setup_io_signatures (int sample_precision,
int n_code_inputs,
int n_code_outputs);
- int d_n_code_inputs, d_n_code_outputs;
decoder_viterbi_full_block* d_decoder;
- encoder_convolutional* d_encoder;
code_input_ptr d_in_buf;
code_output_ptr d_out_buf;
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.i
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.i
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.i
2006-08-21 16:48:00 UTC (rev 3362)
@@ -22,56 +22,14 @@
GR_SWIG_BLOCK_MAGIC(ecc,metrics_decode_viterbi_full_block);
-// corrected "class NAME" statement, which uses slightly different NAMEs
-
-typedef boost::shared_ptr<ecc_metrics_decode_viterbi_full_block>
-ecc_metrics_decode_viterbi_full_block_feedback_sptr;
-
-LOCAL_GR_SWIG_BLOCK_MAGIC(ecc,metrics_decode_viterbi_full_block_feedback);
-
ecc_metrics_decode_viterbi_full_block_sptr
ecc_make_metrics_decode_viterbi_full_block
(int sample_precision,
- int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- const std::vector<int> &code_generator,
- bool do_termination,
- int start_memory_state,
- int end_memory_state);
+ const ecc_streams_encode_convolutional_sptr& encoder);
-ecc_metrics_decode_viterbi_full_block_feedback_sptr
-ecc_make_metrics_decode_viterbi_full_block_feedback
-(int sample_precision,
- int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- const std::vector<int> &code_generator,
- const std::vector<int> &code_feedback,
- bool do_termination,
- int start_memory_state,
- int end_memory_state);
-
class ecc_metrics_decode_viterbi_full_block : public gr_block
{
ecc_metrics_decode_viterbi_full_block
(int sample_precision,
- int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- const std::vector<int> &code_generator,
- bool do_termination,
- int start_memory_state,
- int end_memory_state);
-
- ecc_metrics_decode_viterbi_full_block
- (int sample_precision,
- int frame_size_bits,
- int n_code_inputs,
- int n_code_outputs,
- const std::vector<int> &code_generator,
- const std::vector<int> &code_feedback,
- bool do_termination,
- int start_memory_state,
- int end_memory_state);
+ const ecc_streams_encode_convolutional_sptr& encoder);
};
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.cc
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -35,7 +35,7 @@
int n_code_inputs,
int n_code_outputs,
const std::vector<int> &code_generator,
- bool do_termination,
+ int do_termination,
int start_memory_state,
int end_memory_state)
{
@@ -56,7 +56,7 @@
int n_code_outputs,
const std::vector<int> &code_generator,
const std::vector<int> &code_feedback,
- bool do_termination,
+ int do_termination,
int start_memory_state,
int end_memory_state)
{
@@ -76,21 +76,33 @@
int n_code_inputs,
int n_code_outputs,
const std::vector<int> &code_generators,
- bool do_termination,
+ int do_termination,
int start_memory_state,
int end_memory_state)
: gr_block ("streams_encode_convolutional",
gr_make_io_signature (0, 0, 0),
gr_make_io_signature (0, 0, 0))
{
- // error checking is done by the encoder class itself;
- // just pass items on here.
+ // convert the "do_termination" argument into a "bool" type
+ bool l_do_term = false;
+
+ if (do_termination != 0) {
+ l_do_term = true;
+ if (do_termination != 1) {
+ std::cout << "ecc_streams_encode_convolutional: Warning: "
+ "do_termination is not 0 or 1; using 'true'.\n";
+ }
+ }
+
+ // the rest of the error checking is done by the encoder class
+ // itself; just pass items on here.
+
d_encoder = new encoder_convolutional (frame_size_bits,
n_code_inputs,
n_code_outputs,
code_generators,
- do_termination,
+ l_do_term,
start_memory_state,
end_memory_state);
@@ -103,22 +115,34 @@
int n_code_outputs,
const std::vector<int> &code_generators,
const std::vector<int> &code_feedback,
- bool do_termination,
+ int do_termination,
int start_memory_state,
int end_memory_state)
: gr_block ("streams_encode_convolutional_feedback",
gr_make_io_signature (0, 0, 0),
gr_make_io_signature (0, 0, 0))
{
- // error checking is done by the encoder class itself;
- // just pass items on here.
+ // convert the "do_termination" argument into a "bool" type
+ bool l_do_term = false;
+
+ if (do_termination != 0) {
+ l_do_term = true;
+ if (do_termination != 1) {
+ std::cout << "ecc_streams_encode_convolutional_feedback: Warning: "
+ "do_termination is not 0 or 1; using 'true'.\n";
+ }
+ }
+
+ // the rest of the error checking is done by the encoder class
+ // itself; just pass items on here.
+
d_encoder = new encoder_convolutional (frame_size_bits,
n_code_inputs,
n_code_outputs,
code_generators,
code_feedback,
- do_termination,
+ l_do_term,
start_memory_state,
end_memory_state);
@@ -181,7 +205,7 @@
// compute the actual number of output items (1 bit char's) created.
size_t t_n_input_items = d_encoder->compute_n_input_bits (noutput_items);
-#if 1
+#if 0
size_t t_n_output_items = d_encoder->compute_n_output_bits (t_n_input_items);
assert (t_n_output_items == ((size_t)noutput_items));
#endif
@@ -196,8 +220,6 @@
t_n_input_items = d_encoder->encode (d_in_buf, d_out_buf,
(size_t) noutput_items);
- assert (0);
-
// consume the number of used input items on all input streams
consume_each (t_n_input_items);
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.h
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -79,7 +79,7 @@
int n_code_inputs,
int n_code_outputs,
const std::vector<int> &code_generator,
- bool do_termination = true,
+ int do_termination = 1,
int start_memory_state = 0,
int end_memory_state = 0);
@@ -90,7 +90,7 @@
int n_code_outputs,
const std::vector<int> &code_generator,
const std::vector<int> &code_feedback,
- bool do_termination = true,
+ int do_termination = 1,
int start_memory_state = 0,
int end_memory_state = 0);
@@ -103,7 +103,7 @@
int n_code_inputs,
int n_code_outputs,
const std::vector<int> &code_generator,
- bool do_termination,
+ int do_termination,
int start_memory_state,
int end_memory_state);
@@ -114,7 +114,7 @@
int n_code_outputs,
const std::vector<int> &code_generator,
const std::vector<int> &code_feedback,
- bool do_termination,
+ int do_termination,
int start_memory_state,
int end_memory_state);
@@ -122,7 +122,7 @@
int n_code_inputs,
int n_code_outputs,
const std::vector<int> &code_generator,
- bool do_termination,
+ int do_termination,
int start_memory_state,
int end_memory_state);
@@ -131,7 +131,7 @@
int n_code_outputs,
const std::vector<int> &code_generator,
const std::vector<int> &code_feedback,
- bool do_termination,
+ int do_termination,
int start_memory_state,
int end_memory_state);
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.i
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.i
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.i
2006-08-21 16:48:00 UTC (rev 3362)
@@ -38,7 +38,7 @@
int n_code_inputs,
int n_code_outputs,
const std::vector<int> &code_generator,
- bool do_termination = true,
+ int do_termination = 1,
int start_memory_state = 0,
int end_memory_state = 0);
@@ -49,7 +49,7 @@
int n_code_outputs,
const std::vector<int> &code_generator,
const std::vector<int> &code_feedback,
- bool do_termination = true,
+ int do_termination = 1,
int start_memory_state = 0,
int end_memory_state = 0);
@@ -61,7 +61,7 @@
int n_code_inputs,
int n_code_outputs,
const std::vector<int> &code_generator,
- bool do_termination,
+ int do_termination,
int start_memory_state,
int end_memory_state);
@@ -71,7 +71,7 @@
int n_code_outputs,
const std::vector<int> &code_generator,
const std::vector<int> &code_feedback,
- bool do_termination,
+ int do_termination,
int start_memory_state,
int end_memory_state);
};
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.cc
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -170,7 +170,7 @@
// compute the actual number of output items (1 bit char's) created.
size_t t_n_input_items = d_encoder->compute_n_input_bits (noutput_items);
-#if 1
+#if 0
size_t t_n_output_items = d_encoder->compute_n_output_bits (t_n_input_items);
assert (t_n_output_items == ((size_t)noutput_items));
#endif
@@ -185,8 +185,6 @@
t_n_input_items = d_encoder->encode (d_in_buf, d_out_buf,
(size_t) noutput_items);
- assert (0);
-
// consume the number of used input items on all input streams
consume_each (t_n_input_items);
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.h
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -25,12 +25,7 @@
#include <gr_block.h>
#include <ecc_streams_encode_convolutional.h>
-
-#if 0
-#include <libecc/encoder_turbo_ic1_ic1.h>
-#else
#include <libecc/encoder_turbo.h>
-#endif
/*!
* \brief Encode the incoming stream(s) using a turbo encoder
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -76,14 +76,22 @@
{
// setup the dummy functions to do the conversion from the
// python-provided feval classes to that which is needed by the
- // libecc's code_metrics classes.
+ // libecc's code_syms_to_metrics classes.
l_pdf_fcn_0_bit = pdf_fcn_0_bit;
l_pdf_fcn_1_bit = pdf_fcn_1_bit;
// use the static "create" member function to create the actual
- // code_metrics to use.
+ // code_syms_to_metrics to use.
+<<<<<<< .working
+<<<<<<< .working
+ d_code_metrics_table = libecc_code_syms_to_metrics_create_table<float>
+ (&pdf_fcn_0, &pdf_fcn_1, n_samples,
+ min_sample, max_sample,sample_precision);
+=======
+=======
+>>>>>>> .merge-right.r3361
d_code_metrics_table = libecc_code_metrics_create_table<float>
(&pdf_fcn_0,
&pdf_fcn_1,
@@ -91,13 +99,15 @@
min_sample,
max_sample,
sample_precision);
+>>>>>>> .merge-right.r3343
- // get the output item size in bytes from the new code_metrics.
+ // get the output item size in bytes from the new
+ // code_syms_to_metrics.
d_out_item_size_bytes = d_code_metrics_table->out_item_size_bytes ();
- // set the output signature to match that which the code_metrics
- // will generate.
+ // set the output signature to match that which the
+ // code_syms_to_metrics will generate.
set_output_signature (gr_make_io_signature (1, -1, d_out_item_size_bytes));
}
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.h
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -26,7 +26,7 @@
#include <gr_block.h>
#include <gr_feval.h>
#include <vector>
-#include <libecc/code_metrics.h>
+#include <libecc/code_syms_to_metrics.h>
class ecc_syms_to_metrics;
typedef boost::shared_ptr<ecc_syms_to_metrics> ecc_syms_to_metrics_sptr;
@@ -106,7 +106,17 @@
int sample_precision);
size_t d_out_item_size_bytes;
+<<<<<<< .working
+<<<<<<< .working
+ code_syms_to_metrics<float>* d_code_metrics_table;
+=======
+=======
+>>>>>>> .merge-right.r3361
code_metrics_table<float>* d_code_metrics_table;
+<<<<<<< .working
+>>>>>>> .merge-right.r3343
+=======
+>>>>>>> .merge-right.r3361
public:
~ecc_syms_to_metrics() {delete d_code_metrics_table;};
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/Makefile.am
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/Makefile.am
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/Makefile.am
2006-08-21 16:48:00 UTC (rev 3362)
@@ -30,22 +30,35 @@
libecc_la_SOURCES = \
code_convolutional_trellis.cc \
- code_metrics.cc code_io.cc \
+ code_syms_to_metrics.cc \
+ code_metrics_to_branches.cc \
+ code_io.cc \
encoder.cc \
encoder_convolutional.cc \
encoder_turbo.cc \
decoder.cc \
decoder_viterbi.cc \
- decoder_viterbi_full_block.cc
+ decoder_viterbi_lazy.cc
+# decoder_viterbi_lazy_alt.cc
+# decoder_viterbi_standard.cc
+
noinst_HEADERS = \
- code_types.h code_metrics.h code_io.h \
+ code_types.h \
+ code_syms_to_metrics.h \
+ code_metrics_to_branches.h \
+ code_io.h \
code_convolutional_trellis.h \
- encoder.h encoder_turbo.h \
+ encoder.h \
encoder_convolutional.h \
- decoder.h decoder_viterbi.h \
- decoder_viterbi_full_block.h
+ encoder_turbo.h \
+ decoder.h \
+ decoder_viterbi.h \
+ decoder_viterbi_lazy.h
+# decoder_viterbi_lazy_alt.h
+# decoder_viterbi_standard.h
+
# link the library against the c++ standard library
libecc_la_LIBADD = \
mld/libmld.la \
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.cc
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -430,25 +430,19 @@
// create the trellis for this code:
memory_t t_mask = (memory_t)((1 << d_total_n_delays) - 1);
- memory_t t_end_memory_state = (memory_t) end_memory_state;
+ d_end_memory_state = (memory_t) end_memory_state;
- if (t_end_memory_state != (t_end_memory_state & t_mask)) {
+ if (d_end_memory_state != (d_end_memory_state & t_mask)) {
std::cout << "code_convolutional_trellis: Warning: " <<
"provided end memory state out (" << end_memory_state <<
") is out of the state range [0, " <<
(d_n_states-1) << "]; masking off the unused bits.\n";
- end_memory_state &= t_mask;
+ d_end_memory_state &= t_mask;
}
create_trellis ();
-
- if (d_do_termination == true) {
-
- // create the termination lookup table
-
- create_termination_table (end_memory_state);
- }
+ create_termination_table ();
}
void
@@ -752,7 +746,7 @@
void
code_convolutional_trellis::create_termination_table
-(memory_t end_memory_state)
+()
{
// somewhat involved, but basically start with the terminating state
// and work backwards d_total_n_delays, then create a
@@ -763,6 +757,9 @@
// particular state, listed in order from LSB for the first input
// bit to the MSB for the last input bit.
+ if (d_do_termination == false)
+ return;
+
// create a reverse trellis
// it's temporary, just for doing the termination, so just do it locally
@@ -780,7 +777,7 @@
}
std::vector<memory_t> tmp(d_n_memories);
- demux_state (end_memory_state, tmp);
+ demux_state (d_end_memory_state, tmp);
memory_t to_state, outputs;
connection_t t_conn;
@@ -839,7 +836,7 @@
// create the list of "in-use" states for the current t_term_inputs
- std::vector<size_t> t_used_states_ndx[2];
+ std::vector<memory_t> t_used_states_ndx[2];
t_used_states_ndx[0].assign (d_n_states, 0);
t_used_states_ndx[1].assign (d_n_states, 0);
@@ -856,8 +853,8 @@
// setup the first state
size_t t_which_input = 0;
- t_used_states_ndx[t_which_input][0] = (size_t) end_memory_state;
- t_in_use_states[t_which_input][(size_t) end_memory_state] = true;
+ t_used_states_ndx[t_which_input][0] = d_end_memory_state;
+ t_in_use_states[t_which_input][d_end_memory_state] = true;
size_t n_states_used[2];
n_states_used[t_which_input] = 1;
n_states_used[t_which_input^1] = 0;
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.h
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -164,21 +164,39 @@
inline const bool do_encode_soai () {return (d_do_encode_soai);};
inline const size_t total_n_delays () {return (d_total_n_delays);};
inline const size_t n_bits_to_term () {return (d_n_bits_to_term);};
+ inline const memory_t end_memory_state () {return (d_end_memory_state);};
virtual char sum_bits_mod2 (memory_t in_mem, size_t max_memory);
- void get_termination_inputs (memory_t term_start_state,
- size_t bit_num,
- std::vector<char>& inputs) {
+ inline void get_termination_inputs (memory_t term_start_state,
+ size_t bit_num,
+ std::vector<char>& inputs) {
// no error checking ... be careful!
for (size_t m = 0; m < d_n_code_inputs; m++) {
inputs[m] = ((d_term_inputs[term_start_state][m]) >> bit_num) & 1;
}
};
+ inline memory_t get_termination_inputs (memory_t term_start_state,
+ size_t bit_num) {
+ // no error checking ... be careful!
+ memory_t t_inputs = 0;
+ for (size_t m = 0; m < d_n_code_inputs; m++) {
+ memory_t t_input = ((d_term_inputs[term_start_state][m]) >> bit_num) & 1;
+ t_inputs |= (t_input << m);
+ }
+ return (t_inputs);
+ };
// encode_lookup: given the starting state and inputs, return the
// resulting state and output bits. Two versions: the first is
// better for decoding, while the second is better for encoding.
+ inline void encode_lookup (memory_t& state,
+ const memory_t inputs,
+ memory_t& out_bits) {
+ connection_t_ptr t_connection = &(d_trellis[state][inputs]);
+ state = t_connection->d_to_state;
+ out_bits = t_connection->d_output_bits;
+ };
void encode_lookup (memory_t& state,
const std::vector<char>& inputs,
memory_t& out_bits);
@@ -196,39 +214,7 @@
memory_t mux_outputs (const std::vector<char>& out_vec);
protected:
-#if 0
/*
- * state_get_from(v,i,k): use to retrieve a given bit-memory state,
- * from the inputs:
- *
- * memory_t v: the value from which to retrieve the given state
- * size_t i: for which input stream (0 to #I-1)
- * size_t k: the number of memory slots per input (e.g. 1+D^2 -> 2)
- */
-
- inline memory_t state_get_from (memory_t v,
- size_t i,
- size_t k)
- {return (((v)>>((i)*(k)))&((1<<(k))-1));};
-
-/*
- * state_add_to(s,v,i,k): use to create a given bit-memory state,
- * from the inputs:
- *
- * memory_t s: the state value to modify
- * memory_t v: value to set the state to for this input
- * size_t i: for which input stream (0 to #I-1)
- * size_t k: the number of memory slots per input (e.g. 1+D^2 -> 2)
- */
-
- inline void state_add_to (memory_t s,
- memory_t v,
- size_t i,
- size_t k)
- {(s)|=(((v)&((1<<(k))-1))<<((i)*(k)));};
-#endif
-
-/*
* 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.
@@ -284,7 +270,7 @@
int end_memory_state);
void create_trellis ();
- void create_termination_table (memory_t end_memory_state);
+ void create_termination_table ();
void encode_single (memory_t in_state,
memory_t inputs,
memory_t& out_state,
@@ -400,6 +386,11 @@
// representation for this code; forward paths only
trellis_t d_trellis;
+
+ // "end_memory_state" is the user-provided ending memory
+ // state, interpreted w/r.t. the actual trellis;
+
+ memory_t d_end_memory_state;
};
#endif /* INCLUDED_CODE_CONVOLUTIONAL_TRELLIS_H */
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_io.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_io.h
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_io.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -126,7 +126,7 @@
* "id":
* 'i': one stream per code input as defined by the instantiated
* code ("individual", not mux'ed);
- * 'f': streams of double;
+ * 'd': streams of double;
*/
inline code_input_id (size_t n_streams) : code_input (n_streams) {};
virtual ~code_input_id () {};
@@ -197,7 +197,7 @@
public:
/*!
- * class code_input_is : public code_input
+ * class code_input_ic : public code_input
*
* "ic":
* 'i': one stream per code input as defined by the instantiated
Deleted:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics.cc
Deleted:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics.h
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics_to_branches.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics_to_branches.cc
(rev 0)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics_to_branches.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -0,0 +1,145 @@
+/* -*- 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 "code_metrics_to_branches.h"
+#include <iostream>
+#include <assert.h>
+
+code_metrics_to_branches*
+libecc_code_metrics_to_branches_create
+(const code_convolutional_trellis* trellis,
+ int sample_precision)
+{
+ if (trellis == 0) {
+ std::cerr << "libecc_code_metrics_to_branches_create: Error: "
+ "Trellis is NULL.\n";
+ assert (0);
+ }
+
+ if ((sample_precision < 0) | (sample_precision > 32)) {
+ std::cerr << "libecc_code_metrics_to_branches_create: Error: "
+ "sample_precision must be between 0 and 32.\n";
+ assert (0);
+ }
+
+ code_metrics_to_branches* t_code_metrics_to_branches = 0;
+
+ if (sample_precision == 0) {
+ // float for metric and computations
+ t_code_metrics_to_branches = new
+ code_metrics_to_branches_work<float,float>(trellis);
+ } else if (sample_precision <= 8) {
+ // use char for metrics, long for computations
+ t_code_metrics_to_branches = new
+ code_metrics_to_branches_work<unsigned char,unsigned long>(trellis);
+ } else if (sample_precision <= 16) {
+ // use short for metrics, long for computations
+ t_code_metrics_to_branches = new
+ code_metrics_to_branches_work<unsigned short,unsigned long>(trellis);
+ } else {
+ // use long for metrics, long for computations
+ t_code_metrics_to_branches = new
+ code_metrics_to_branches_work<unsigned long,unsigned long>(trellis);
+ }
+
+ return (t_code_metrics_to_branches);
+}
+
+code_metrics_to_branches::code_metrics_to_branches
+(const code_convolutional_trellis* trellis)
+{
+ d_n_code_outputs = ((code_convolutional_trellis*) trellis)->n_code_outputs
();
+}
+
+template<typename metric_t, typename computation_t>
+void
+code_metrics_to_branches_work<metric_t,computation_t>::compute_all_branches
+(void* t_input_metrics,
+ void* t_branches)
+{
+ metric_t_hdl metrics = (metric_t_hdl) t_input_metrics;
+ computation_t_ptr out = (computation_t_ptr) t_branches;
+
+ // compute all possible (summation) combinations of the metrics
+ // using <computation_t>-precision (e.g. "float") computations and
+ // return those in the provided vector.
+
+ // the input metrics must be a [2][d_n_code_outputs] "matrix", with
+ // the [0][] and [1][] entries representing p(0|sym) and p(1|sym),
+ // respectively.
+
+ // the output "table" must be a [1 << d_n_code_outputs] "vector",
+ // where each entry represents the combined (added) metric for that
+ // given set of output bits. e.g. [6] (== 110 in binary) would be
+ // the sum of metrics for p(1|sym#2), p(1|sym#1), and p(0|sym#0)
+
+ // assign the starting minimum metric to 0. This is safe because
+ // metrics are always non-negative.
+
+ computation_t min_metric = 0;
+ for (size_t m = 0; m < (((size_t)1) << d_n_code_outputs); m++) {
+ size_t t_out_ndx = m;
+ computation_t t_metric = 0;
+ for (size_t n = 0; n < d_n_code_outputs; n++, t_out_ndx >>= 1)
+ t_metric += metrics[t_out_ndx&1][n];
+ if (t_metric < min_metric)
+ min_metric = t_metric;
+ out[m] = t_metric;
+ }
+
+ // normalize so that the minimum metric always equals 0
+
+ for (size_t m = 0; m < d_n_code_outputs; m++)
+ out[m] -= min_metric;
+}
+
+#if 0
+// force instantiation all used versions of the templates
+
+template
+void
+code_metrics_to_branches_work<float,float>::compute_all_outputs
+(void* t_metrics,
+ void* t_out);
+
+template
+void
+code_metrics_to_branches_work<unsigned char,unsigned long>::compute_all_outputs
+(void* t_metrics,
+ void* t_out);
+
+template
+void
+code_metrics_to_branches_work<unsigned short,unsigned
long>::compute_all_outputs
+(void* t_metrics,
+ void* t_out);
+
+template
+void
+code_metrics_to_branches_work<unsigned long,unsigned long>::compute_all_outputs
+(void* t_metrics,
+ void* t_out);
+#endif
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics_to_branches.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics_to_branches.h
(rev 0)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_metrics_to_branches.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -0,0 +1,74 @@
+/* -*- 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_CODE_METRICS_TO_BRANCHES_H
+#define INCLUDED_CODE_METRICS_TO_BRANCHES_H
+
+#include "code_convolutional_trellis.h"
+
+class code_metrics_to_branches;
+
+code_metrics_to_branches*
+libecc_code_metrics_to_branches_create
+(const code_convolutional_trellis* trellis,
+ int sample_precision = 10);
+
+class code_metrics_to_branches
+{
+public:
+ // compute all possible output-bit branches of the incoming metrics
+
+ virtual void compute_all_branches (void* t_input_metrics,
+ void* t_branches) = 0;
+
+ virtual ~code_metrics_to_branches () {};
+
+protected:
+ code_metrics_to_branches (const code_convolutional_trellis* trellis);
+
+ size_t d_n_code_outputs;
+};
+
+template<typename metric_t, typename computation_t>
+class code_metrics_to_branches_work : public code_metrics_to_branches
+{
+public:
+ typedef metric_t *metric_t_ptr, **metric_t_hdl;
+ typedef computation_t * computation_t_ptr;
+
+ virtual void compute_all_branches (void* t_input_metrics,
+ void* t_branches);
+
+ virtual ~code_metrics_to_branches_work () {};
+
+protected:
+ inline code_metrics_to_branches_work
+ (const code_convolutional_trellis* trellis) :
+ code_metrics_to_branches (trellis) {};
+
+ friend code_metrics_to_branches*
+ libecc_code_metrics_to_branches_create
+ (const code_convolutional_trellis* trellis,
+ int sample_precision);
+};
+
+#endif /* INCLUDED_CODE_METRICS_TO_BRANCHES_H */
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_syms_to_metrics.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_syms_to_metrics.cc
(rev 0)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_syms_to_metrics.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -0,0 +1,340 @@
+/* -*- 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 <code_syms_to_metrics.h>
+#include <iostream>
+#include <math.h>
+#include <assert.h>
+
+template<typename pdf_fcn_io_t>
+code_syms_to_metrics<pdf_fcn_io_t>*
+libecc_code_syms_to_metrics_create_table
+(pdf_fcn_io_t (*pdf_fcn_0_bit) (pdf_fcn_io_t),
+ pdf_fcn_io_t (*pdf_fcn_1_bit) (pdf_fcn_io_t),
+ size_t n_samples,
+ pdf_fcn_io_t min_sample,
+ pdf_fcn_io_t max_sample,
+ int sample_precision)
+{
+ if (! pdf_fcn_0_bit) {
+ std::cerr << "libecc_code_syms_to_metrics_create_table: Error: "
+ "pdf_fcn_0_bit must be a non-null pointer to function.\n";
+ assert (0);
+ }
+ if (! pdf_fcn_1_bit) {
+ std::cerr << "libecc_code_syms_to_metrics_create_table: Error: "
+ "pdf_fcn_0_bit must be a non-null pointer to function.\n";
+ assert (0);
+ }
+ if (n_samples < 2) {
+ std::cerr << "libecc_code_syms_to_metrics_create_table: Error: "
+ "n_samples must be at least 2.\n";
+ assert (0);
+ }
+ if (min_sample >= max_sample) {
+ std::cerr << "libecc_code_syms_to_metrics_create_table: Error: "
+ "min_sample must be less than max_sample.\n";
+ assert (0);
+ }
+ if ((sample_precision < 0) | (sample_precision > 32)) {
+ std::cerr << "libecc_code_syms_to_metrics_create_table: Error: "
+ "sample_precision must be between 0 and 32.\n";
+ assert (0);
+ }
+
+ code_syms_to_metrics<pdf_fcn_io_t>* t_code_syms_to_metrics = 0;
+
+ if (sample_precision == 0) {
+ // float
+ t_code_syms_to_metrics = new code_syms_to_metrics_work
+ <pdf_fcn_io_t, float>(pdf_fcn_0_bit,
+ pdf_fcn_1_bit,
+ n_samples,
+ min_sample,
+ max_sample);
+ } else if (sample_precision <= 8) {
+ // use char
+ t_code_syms_to_metrics = new code_syms_to_metrics_work
+ <pdf_fcn_io_t, unsigned char>(pdf_fcn_0_bit,
+ pdf_fcn_1_bit,
+ n_samples,
+ min_sample,
+ max_sample,
+ sample_precision);
+ } else if (sample_precision <= 16) {
+ // use short
+ t_code_syms_to_metrics = new code_syms_to_metrics_work
+ <pdf_fcn_io_t, unsigned short>(pdf_fcn_0_bit,
+ pdf_fcn_1_bit,
+ n_samples,
+ min_sample,
+ max_sample,
+ sample_precision);
+ } else {
+ // use long
+ t_code_syms_to_metrics = new code_syms_to_metrics_work
+ <pdf_fcn_io_t, unsigned long>(pdf_fcn_0_bit,
+ pdf_fcn_1_bit,
+ n_samples,
+ min_sample,
+ max_sample,
+ sample_precision);
+ }
+
+ return (t_code_syms_to_metrics);
+}
+
+template<typename pdf_fcn_io_t>
+code_syms_to_metrics<pdf_fcn_io_t>::code_syms_to_metrics
+(pdf_fcn_t pdf_fcn_0_bit,
+ pdf_fcn_t pdf_fcn_1_bit,
+ size_t n_samples,
+ pdf_fcn_io_t min_sample,
+ pdf_fcn_io_t max_sample)
+{
+ // internally, all samples are taken as pdf_fcn_io_t initially, and
+ // only converted to other values by their specific constructors.
+
+ d_n_samples = n_samples;
+ d_max_sample = max_sample;
+ d_min_sample = min_sample;
+ d_delta = (max_sample - min_sample) / ((pdf_fcn_io_t) n_samples);
+ d_pdf_fcn_0_bit = pdf_fcn_0_bit;
+ d_pdf_fcn_1_bit = pdf_fcn_1_bit;
+
+ // use a sub-sample by 100 to better determine the actual "bin"
+ // probability values for each actual sample. Each "bin" is 100
+ // delta's less than the min_sample up to the min_sample+delta; then
+ // each delta; then from the max_sample-delta to 100 delta's more
+ // than the max sample. Once normalized, these give a reasonable
+ // interpretation of the PDF function.
+
+ pdf_fcn_io_t d_sub_delta = d_delta / ((pdf_fcn_io_t) 100);
+ pdf_fcn_io_t d_sub_min_sample = d_min_sample - ((pdf_fcn_io_t) 100)*d_delta;
+ pdf_fcn_io_t d_sup_max_sample = d_max_sample + ((pdf_fcn_io_t) 100)*d_delta;
+
+ d_pdf_fcn_0_samples.assign (d_n_samples, 0);
+ d_pdf_fcn_1_samples.assign (d_n_samples, 0);
+
+ pdf_fcn_io_t t_val, t_sum_0, t_sum_1, t_max_0, t_max_1, t_min_0, t_min_1;
+ t_sum_0 = t_sum_1 = t_max_0 = t_max_1 = t_min_0 = t_min_1 = 0;
+ size_t m = 0;
+ t_val = d_sub_min_sample;
+ for (; m < (d_n_samples - 1); m++) {
+ pdf_fcn_io_t t_sample_0 = 1;
+ pdf_fcn_io_t t_sample_1 = 1;
+ for (; t_val < (d_min_sample+d_delta); t_val += d_sub_delta) {
+ t_sample_0 += ((*d_pdf_fcn_0_bit)(t_val));
+ t_sample_1 += ((*d_pdf_fcn_1_bit)(t_val));
+ }
+ d_pdf_fcn_0_samples[m] = t_sample_0;
+ d_pdf_fcn_0_samples[m] = t_sample_1;
+ t_sum_0 += t_sample_0;
+ t_sum_1 += t_sample_1;
+ if (m == 0) {
+ t_max_0 = t_min_0 = t_sample_0;
+ t_max_1 = t_min_1 = t_sample_1;
+ } else {
+ if (t_max_0 < t_sample_0)
+ t_max_0 = t_sample_0;
+ else if (t_min_0 > t_sample_0)
+ t_min_0 = t_sample_0;
+ if (t_max_1 < t_sample_1)
+ t_max_1 = t_sample_1;
+ else if (t_min_1 > t_sample_1)
+ t_min_1 = t_sample_1;
+ }
+ }
+
+ pdf_fcn_io_t t_sample_0 = 1;
+ pdf_fcn_io_t t_sample_1 = 1;
+ for (; t_val < d_sup_max_sample; t_val += d_sub_delta) {
+ t_sample_0 += ((*d_pdf_fcn_0_bit)(t_val));
+ t_sample_1 += ((*d_pdf_fcn_1_bit)(t_val));
+ }
+ d_pdf_fcn_0_samples[m] = t_sample_0;
+ d_pdf_fcn_0_samples[m] = t_sample_1;
+ t_sum_0 += t_sample_0;
+ t_sum_1 += t_sample_1;
+ if (t_max_0 < t_sample_0)
+ t_max_0 = t_sample_0;
+ else if (t_min_0 > t_sample_0)
+ t_min_0 = t_sample_0;
+ if (t_max_1 < t_sample_1)
+ t_max_1 = t_sample_1;
+ else if (t_min_1 > t_sample_1)
+ t_min_1 = t_sample_1;
+
+ // normalize to the sum, so that these are "real" probabilities.
+
+ for (m = 0; m < d_n_samples; m++) {
+ d_pdf_fcn_0_samples[m] /= t_sum_0;
+ d_pdf_fcn_1_samples[m] /= t_sum_1;
+ }
+ t_max_0 /= t_sum_0;
+ t_min_0 /= t_sum_0;
+ t_max_1 /= t_sum_1;
+ t_min_1 /= t_sum_1;
+
+ // take the logf so that metrics can add
+
+ for (m = 0; m < d_n_samples; m++) {
+ d_pdf_fcn_0_samples[m] = logf (d_pdf_fcn_0_samples[m]);
+ d_pdf_fcn_1_samples[m] = logf (d_pdf_fcn_1_samples[m]);
+ }
+ t_max_0 = logf (t_max_0);
+ t_min_0 = logf (t_min_0);
+ t_max_1 = logf (t_max_1);
+ t_min_1 = logf (t_min_1);
+
+ // higher (less negative) log-probabilities mean more likely; lower
+ // (more negative) mean less likely. Want metrics which are 0 when
+ // most likely and more positive when less likely. So subtract the
+ // max, then negate and normalize to the min (new max) so that the
+ // max value is 1 and the min value is 0.
+
+ for (m = 0; m < d_n_samples; m++) {
+ d_pdf_fcn_0_samples[m] = ((d_pdf_fcn_0_samples[m] - t_max_0) /
+ (t_min_0 - t_max_0));
+ d_pdf_fcn_1_samples[m] = ((d_pdf_fcn_1_samples[m] - t_max_1) /
+ (t_min_1 - t_max_1));
+ }
+
+ // correct the delta to the lookup computations
+
+ d_delta = (max_sample - min_sample) / ((pdf_fcn_io_t)(n_samples-1));
+}
+
+template<typename pdf_fcn_io_t, typename metric_t>
+code_syms_to_metrics_work<pdf_fcn_io_t,metric_t>::code_syms_to_metrics_work
+(pdf_fcn_t pdf_fcn_0_bit,
+ pdf_fcn_t pdf_fcn_1_bit,
+ size_t n_samples,
+ pdf_fcn_io_t min_sample,
+ pdf_fcn_io_t max_sample,
+ int sample_precision)
+ : code_syms_to_metrics<pdf_fcn_io_t>
+ (pdf_fcn_0_bit,
+ pdf_fcn_1_bit,
+ n_samples,
+ min_sample,
+ max_sample)
+{
+ code_syms_to_metrics<pdf_fcn_io_t>::d_out_item_size_bytes = sizeof
(metric_t);
+ code_syms_to_metrics<pdf_fcn_io_t>::d_sample_precision = sample_precision;
+
+ // get the scale factor for converting from float to
+ // sample_precision maps: 0 -> 0, 1 -> (2^sample_precision)-1 for
+ // integers; there is no need for a mapping for float types, since
+ // those are already in [0,1].
+
+ pdf_fcn_io_t t_mult = ((sample_precision == 0) ? 1 :
+ ((pdf_fcn_io_t)((2^sample_precision)-1)));
+
+ // convert the 0 bit metrics from float to integer
+
+ d_metric_table_0_bit.assign (n_samples, 0);
+ for (size_t m = 0; m < n_samples; m++) {
+ d_metric_table_0_bit[m] =
+ (metric_t)((code_syms_to_metrics<pdf_fcn_io_t>::d_pdf_fcn_0_samples[m]) *
+ t_mult);
+ }
+
+ // clear the old float sample vectors to free memory
+
+ code_syms_to_metrics<pdf_fcn_io_t>::d_pdf_fcn_0_samples.resize (0);
+
+ // convert the 1 bit metrics from float to integer
+
+ d_metric_table_1_bit.assign (n_samples, 0);
+ for (size_t m = 0; m < n_samples; m++) {
+ d_metric_table_1_bit[m] =
+ (metric_t)((code_syms_to_metrics<pdf_fcn_io_t>::d_pdf_fcn_1_samples[m]) *
+ t_mult);
+ }
+
+ // clear the old float sample vectors to free memory
+
+ code_syms_to_metrics<pdf_fcn_io_t>::d_pdf_fcn_1_samples.resize (0);
+}
+
+template<typename pdf_fcn_io_t, typename metric_t>
+void
+code_syms_to_metrics_work<pdf_fcn_io_t,metric_t>::lookup
+(pdf_fcn_io_t sym,
+ void* bit_0,
+ void* bit_1)
+{
+ metric_t_ptr l_bit_0 = (metric_t_ptr) bit_0;
+ metric_t_ptr l_bit_1 = (metric_t_ptr) bit_1;
+
+ if (sym <= code_syms_to_metrics<pdf_fcn_io_t>::d_min_sample) {
+ *l_bit_0 = d_metric_table_0_bit[0];
+ *l_bit_1 = d_metric_table_1_bit[0];
+ return;
+ }
+ if (sym >= code_syms_to_metrics<pdf_fcn_io_t>::d_max_sample) {
+ *l_bit_0 = d_metric_table_0_bit.back ();
+ *l_bit_1 = d_metric_table_1_bit.back ();
+ return;
+ }
+
+ size_t l_ndx = (size_t) round
+ ((double)((sym - code_syms_to_metrics<pdf_fcn_io_t>::d_min_sample) /
+ code_syms_to_metrics<pdf_fcn_io_t>::d_delta));
+ *l_bit_0 = d_metric_table_0_bit[l_ndx];
+ *l_bit_1 = d_metric_table_1_bit[l_ndx];
+}
+
+template<typename pdf_fcn_io_t, typename metric_t>
+void
+code_syms_to_metrics_work<pdf_fcn_io_t,metric_t>::convert
+(size_t n_syms,
+ pdf_fcn_io_t* sym,
+ void* bit_0,
+ void* bit_1)
+{
+ metric_t_ptr l_bit_0 = (metric_t_ptr) bit_0;
+ metric_t_ptr l_bit_1 = (metric_t_ptr) bit_1;
+
+ for (size_t m = n_syms; m > 0; m--)
+ lookup (*sym++, (void*) l_bit_0++, (void*) l_bit_1++);
+}
+
+// force the compiler to instantiate a particular version of the
+// templated super-class, for <float> PDF function precision because
+// all code_syms_to_metrics classes are created by this function, this is the
+// only one which is required to instantaite.
+
+template
+code_syms_to_metrics<float>*
+libecc_code_syms_to_metrics_create_table<float>
+(float (*pdf_fcn_0_bit) (float),
+ float (*pdf_fcn_1_bit) (float),
+ size_t n_samples,
+ float min_sample,
+ float max_sample,
+ int sample_precision);
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_syms_to_metrics.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_syms_to_metrics.h
(rev 0)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_syms_to_metrics.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -0,0 +1,150 @@
+/* -*- 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_CODE_SYMS_TO_METRICS_H
+#define INCLUDED_CODE_SYMS_TO_METRICS_H
+
+#include "code_types.h"
+#include <vector>
+
+template<typename pdf_fcn_io_t>
+class code_syms_to_metrics;
+
+template<typename pdf_fcn_io_t>
+code_syms_to_metrics<pdf_fcn_io_t>*
+libecc_code_syms_to_metrics_create_table
+(pdf_fcn_io_t (*pdf_fcn_0_bit) (pdf_fcn_io_t),
+ pdf_fcn_io_t (*pdf_fcn_1_bit) (pdf_fcn_io_t),
+ size_t n_samples,
+ pdf_fcn_io_t min_sample,
+ pdf_fcn_io_t max_sample,
+ int sample_precision = 10);
+
+template<typename pdf_fcn_io_t>
+class code_syms_to_metrics
+{
+/*
+ * class code_syms_to_metrics: metrics table for convolutional
+ * codes. Pre-compute a lookup table upon instantiation, which makes
+ * for quick conversion from soft-float symbol value ('sym') to metric
+ * value. The symbol value probability is defined by the arguments
+ * 'pdf_fcn_0_bit' and 'pdf_fcn_1_bit' for p(0|sym) and p(1|sym)
+ * respectively. Internally, the PDF's are sampled and normalized to
+ * always have a minimum value of 0. For float-precision, the maximum
+ * value is 1.0, while for integer M-bits the maximum value is
+ * (2^M)-1. Smaller metric values indicate that the received symbols
+ * are closer to the given output bits; larger values indicate greater
+ * differences. The only constraint on the PDF functions are that
+ * they are piecewise continuous; otherwise, they don't even have to
+ * be a true PDF in terms of the integral from -inf to +inf being
+ * equal to 1 due to the normalization.
+ *
+ * Storage type for the tables is determined by the "sample_precision"
+ * argument. When the precision equals 0, 32-bit float storage is
+ * used; otherwise, the next largest standard integer type is used
+ * unsigned (char for 1 to 8 bits, short for 9 to 16 bits, and long
+ * for 17 to 32 bits). For the purposes of coding gain, any
+ * sample_precision larger than about 9 will have minimal added
+ * benefit under most conditions where communications are possible.
+ * Trellis computations are performed in either 32-bit float (for
+ * float storage) or 32-bit unsigned long (for all integer storage).
+ *
+ * The number of samples to store is determined by the "n_samples"
+ * argument, which must be at least 2 but is otherwise not limited
+ * except by the memory of the host computer.
+ *
+ * Samples of the PDF functions are taken from "min_sample" to
+ * "max_sample", which represent the floor and ceiling on input symbol
+ * values below and above which symbol values are truncated.
+ * Internally, a sub-n_samples value is determined and used to "sum"
+ * the PDF functions to divide the probabilities into "bins".
+ */
+
+public:
+ typedef pdf_fcn_io_t (*pdf_fcn_t) (pdf_fcn_io_t);
+
+ virtual ~code_syms_to_metrics () {};
+
+ // lookup() returns either a float, or a sign-extended
+ // 'sample_precision'-bit integer value.
+
+ virtual void lookup (pdf_fcn_io_t sym,
+ void* bit_0,
+ void* bit_1) = 0;
+
+ // convert does a lookup on 'n_syms' input symbols
+
+ virtual void convert (size_t n_syms,
+ pdf_fcn_io_t* syms,
+ void* bit_0,
+ void* bit_1) = 0;
+
+ inline const unsigned char out_item_size_bytes ()
+ {return(d_out_item_size_bytes);};
+
+protected:
+ code_syms_to_metrics (pdf_fcn_t pdf_fcn_0_bit,
+ pdf_fcn_t pdf_fcn_1_bit,
+ size_t n_samples,
+ pdf_fcn_io_t min_sample,
+ pdf_fcn_io_t max_sample);
+
+ unsigned char d_out_item_size_bytes, d_sample_precision;
+ size_t d_n_samples;
+ pdf_fcn_io_t d_max_sample, d_min_sample, d_delta;
+ pdf_fcn_t d_pdf_fcn_0_bit, d_pdf_fcn_1_bit;
+ std::vector<pdf_fcn_io_t> d_pdf_fcn_0_samples, d_pdf_fcn_1_samples;
+};
+
+template<typename pdf_fcn_io_t, typename metric_t>
+class code_syms_to_metrics_work : public code_syms_to_metrics<pdf_fcn_io_t>
+{
+public:
+ typedef metric_t *metric_t_ptr;
+ typedef pdf_fcn_io_t (*pdf_fcn_t) (pdf_fcn_io_t);
+
+ ~code_syms_to_metrics_work () {};
+
+ void lookup (pdf_fcn_io_t sym, void* bit_0, void* bit_1);
+ void convert (size_t n_syms, pdf_fcn_io_t* sym, void* bit_0, void* bit_1);
+
+protected:
+ code_syms_to_metrics_work (pdf_fcn_t pdf_fcn_0_bit,
+ pdf_fcn_t pdf_fcn_1_bit,
+ size_t n_samples,
+ pdf_fcn_io_t min_sample,
+ pdf_fcn_io_t max_sample,
+ int sample_precision = 10);
+
+ friend code_syms_to_metrics<pdf_fcn_io_t>*
+ libecc_code_syms_to_metrics_create_table<pdf_fcn_io_t>
+ (pdf_fcn_io_t (*pdf_fcn_0_bit) (pdf_fcn_io_t),
+ pdf_fcn_io_t (*pdf_fcn_1_bit) (pdf_fcn_io_t),
+ size_t n_samples,
+ pdf_fcn_io_t min_sample,
+ pdf_fcn_io_t max_sample,
+ int sample_precision);
+
+ std::vector<metric_t> d_metric_table_0_bit, d_metric_table_1_bit;
+};
+
+#endif /* INCLUDED_CODE_SYMS_TO_METRICS_H */
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_types.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_types.h
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/code_types.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -26,6 +26,6 @@
// the following is the type used for encoder memory
-typedef unsigned long memory_t, *memory_ptr_t;
+typedef u_int32_t memory_t, *memory_ptr_t;
#endif /* INCLUDED_CODE_TYPES_H */
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.cc
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -27,1086 +27,263 @@
#include <decoder_viterbi.h>
#include <assert.h>
#include <iostream>
+#include <math.h> // for ceilf ()
-const int g_max_block_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
+#define DO_PRINT_DEBUG_VARS 0
+#define DO_PRINT_DEBUG_FSM 0
#include <mld/mld_timer.h>
#include <mld/n2bs.h>
-
-#if 0
-// at instantiation
-
- // for compute_all_outputs
-
- in_l[0].resize (d_n_code_outputs);
- in_l[1].resize (d_n_code_outputs);
- in_f[0].resize (d_n_code_outputs);
- in_f[1].resize (d_n_code_outputs);
-#endif
-
-#if 0
-template<typename pdf_fcn_io_t, typename computation_t>
-void
-code_metrics<pdf_fcn_io_t>::compute_all_outputs
-(pdf_fcn_io_t* syms,
- std::vector<computation_t>& out)
+template<typename computation_t>
+decoder_viterbi<computation_t>::decoder_viterbi
+(const encoder_convolutional* encoder,
+ u_int8_t sample_precision,
+ bool full_or_partial,
+ u_int32_t n_bits_before_decode)
{
- // use the first 'n_code_output' symbols, convert them into metrics,
- // then call the other "compute_all_outputs"
-
- convert (d_n_code_outputs, syms,
- (void*)(&(in_c[0][0])), (void*)(&in_c[1][0]));
-
- compute_all_outputs (&(in_c[0][0]), out);
-}
-
-template<typename metric_t, typename computation_t>
-void
-code_metrics<metric_t>::compute_all_outputs
-(metric_t** metrics,
- std::vector<computation_t>& out)
-{
- // compute all possible (summation) combinations of the metrics
- // using <computation_t>-precision (e.g. "float") computations and
- // return those in the provided vector.
-
- // the input metrics must be a [2][d_n_code_outputs] "matrix", with
- // the [0][] and [1][] entries representing p(0|sym) and p(1|sym),
- // respectively.
-
- // assign the starting minimum metric to 0. This is safe because
- // metrics are always non-negative.
-
- computation_t min_metric = 0;
- for (size_t m = 0; m < (((size_t)1) << d_n_code_outputs); m++) {
- size_t t_out_ndx = m;
- computation_t t_metric = 0;
- for (size_t n = 0; n < d_n_code_outputs; n++, t_out_ndx >>= 1)
- t_metric += metrics[t_out_ndx&1][n];
- if (t_metric < min_metric)
- min_metric = t_metric;
- out[m] = t_metric;
- }
-
- // normalize so that the minimum metric equals 0
-
- for (size_t m = 0; m < d_n_code_outputs; m++)
- out[m] -= min_metric;
-}
-#endif
-
-decoder_viterbi::decoder_viterbi
-(int sample_precision,
- const encoder_convolutional* l_encoder)
-{
// make sure that the encoder is "valid"
- if (! l_encoder) {
+ if (! encoder) {
std::cerr << "decoder_viterbi: Error: Encoder is NULL.\n";
assert (0);
}
- // make the metrics converter
+ // make sure the sample precision is valid
- // d_code_metrics = new code_metrics (
-
- if ((sample_precision < 0) | (sample_precision > 32)) {
- std::cerr << "decoder_viterbi: "
- "Requested sample_precision (" << sample_precision <<
- ") must be between 0 and 32.\n";
+ if (sample_precision == 0) {
+ // FIXME : very different setup for float
+ std::cout << "decoder_viterbi:: Not set up for <float> precision yet"
+ " ... sorry.\n";
assert (0);
+ } else if (sample_precision > 32) {
+ std::cout << "decoder_viterbi:: Error: Provided sample precision (" <<
+ ((int)sample_precision) << ") must be in the range [0,32].\n";
+ assert (0);
}
// get the trellis
- d_encoder = (encoder_convolutional*) l_encoder;
- d_trellis = (code_convolutional_trellis*) d_encoder->trellis ();
+ d_encoder = (code_convolutional_trellis*) encoder;
+ d_trellis = d_encoder->trellis ();
// fill the class variables
- d_block_size_bits = d_encoder->block_size_bits ();
- d_n_code_inputs = d_encoder->n_code_inputs ();
- d_n_code_outputs = d_encoder->n_code_outputs ();
- d_do_termination = d_encoder->do_termination ();
- d_total_n_delays = d_encoder->total_n_delays ();
+ d_block_size_bits = d_trellis->block_size_bits ();
+ d_n_code_inputs = d_trellis->n_code_inputs ();
+ d_n_code_outputs = d_trellis->n_code_outputs ();
+ d_do_termination = d_trellis->do_termination ();
+ d_n_bits_to_term = d_trellis->n_bits_to_term ();
d_n_states = d_trellis->n_states ();
d_n_input_combinations = d_trellis->n_input_combinations ();
+ d_do_streaming = d_trellis->do_streaming ();
- // really nothing else to do here, since this class doesn't "know"
- // how to process streaming versus block decoding, or partial
- // trellis versus full-trellis. Those will be handled by
- // sub-classes which inherit from this one.
+ // make sure the number of bits before decode make sense
- if (DO_PRINT_DEBUG_INST_0) {
- std::cout << "Init:\n" <<
- "d_block_size_bits = " << d_block_size_bits << "\n" <<
- "d_n_code_inputs = " << d_n_code_inputs << "\n" <<
- "d_n_code_outputs = " << d_n_code_outputs << "\n" <<
- "d_do_termination = " <<
- ((d_do_termination == true) ? "true" : "false") << "\n" <<
- "d_total_n_delays = " << d_total_n_delays << "\n" <<
- "d_n_states = " << d_n_states << "\n" <<
- "d_n_input_combinations = " << d_n_input_combinations << "\n";
+ if ((full_or_partial == G_LIBECC_DECODE_PARTIAL) &
+ (d_do_streaming == false)) {
+ size_t total_block_size_bits = d_block_size_bits;
+ if (d_do_termination == true)
+ total_block_size_bits += d_n_bits_to_term;
+ if (n_bits_before_decode >= total_block_size_bits) {
+ std::cout << "decoder_viterbi:: Warning: Provided # of bit-time "
+ "inputs to process before decoding one bit (" <<
+ n_bits_before_decode << ") is larger than the total block size "
+ "including any termination bits (" << total_block_size_bits <<
+ "). Reverting to full block decoding.\n";
+ }
+ full_or_partial = G_LIBECC_DECODE_FULL;
}
- // always start the fsm in the "init" state
+ d_do_full_or_partial = full_or_partial;
- d_fsm_state = fsm_dec_viterbi_init;
+ if ((n_bits_before_decode == 0) &
+ (d_do_full_or_partial == G_LIBECC_DECODE_PARTIAL)) {
- // create a vector of indexes to states when doing "up" or "termination";
+ // set the number of bits to 5.3 constraint lengths, rounded up
+ n_bits_before_decode =
+ (size_t) ceilf (((float) 5.3) *
+ (((float) d_trellis->total_n_delays ()) + 1));
+ }
- d_up_term_states_ndx[0] = new size_t [d_n_states];
- d_up_term_states_ndx[1] = new size_t [d_n_states];
+ d_n_bits_before_decode = n_bits_before_decode;
- // get the total number of out bits per stream
+ if (d_do_full_or_partial == G_LIBECC_DECODE_FULL) {
+ // full block decoding checks
- d_n_total_inputs_per_stream = d_block_size_bits;
- if (d_do_termination == true)
- d_n_total_inputs_per_stream += d_total_n_delays;
-}
+ // verify that the block size is non-zero
-decoder_viterbi::~decoder_viterbi
-()
-{
- // reverse over from allocation
-#if 0
- delete [] d_up_term_states_ndx[0];
- delete [] d_up_term_states_ndx[1];
+ if (d_block_size_bits == 0) {
+ std::cerr << "decoder_viterbi_full: Error: "
+ "Block size is 0, indicating partial block or stream decoding ... "
+ "must be positive for block decoding.\n";
+ assert (0);
+ }
- // delete the state's structures
+ // set the total number of encoder-output bits per stream for full
+ // block processing, this is the block size + any termination bits
- 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;
+ d_total_n_inputs_per_stream = d_block_size_bits;
+ if (d_do_termination == true)
+ d_total_n_inputs_per_stream += d_n_bits_to_term;
+
+ // create the state trellis; for full/block, use the total # of
+ // time-bits to decode + 1: each set of inputs is represented by a
+ // transition between traceback elements.
+
+ d_n_state_trellis_time_bits = d_total_n_inputs_per_stream + 1;
+
+ // set up the nodes w/ the correct number to pre-allocate
+
+ d_total_n_nodes_to_alloc = d_total_n_inputs_per_stream * d_n_states;
+ } else {
+ // partial
+
+ // set the total number of encoder-output bits per stream for full
+ // block processing, this is the block size + any termination bits
+
+ d_total_n_inputs_per_stream = d_n_bits_before_decode;
+
+ // create the state trellis; for partial, use the total # of
+ // time-bits to decode + 1: each set of inputs is represented by a
+ // transition between traceback elements.
+
+ d_n_state_trellis_time_bits = d_total_n_inputs_per_stream + 1;
+
+ // set up the nodes w/ the correct number to pre-allocate
+
+ d_total_n_nodes_to_alloc = d_total_n_inputs_per_stream * d_n_states;
}
- 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;
+ if (DO_PRINT_DEBUG_VARS) {
+ std::cout << "Decoder Viterbi Init:\n"
+ "block_size_bits = " << d_block_size_bits << "\n"
+ "n_code_inputs = " << d_n_code_inputs << "\n"
+ "n_code_outputs = " << d_n_code_outputs << "\n"
+ "do_termination = " <<
+ ((d_do_termination == true) ? "true" : "false") << "\n"
+ "n_bits_to_term = " << d_n_bits_to_term << "\n"
+ "n_states = " << d_n_states << "\n"
+ "n_input_combinations = " << d_n_input_combinations << "\n"
+ "do_streaming = " <<
+ ((d_do_streaming == true) ? "true" : "false") << "\n"
+ "do_full_or_partial = " <<
+ ((d_do_full_or_partial == G_LIBECC_DECODE_FULL) ?
+ "full" : "partial") << "\n" <<
+ "n_bits_before_decode = " << d_n_bits_before_decode << "\n"
+ "total_n_nodes_to_alloc = " << d_total_n_nodes_to_alloc << "\n"
+ "total_n_inputs_per_stream = " << d_total_n_inputs_per_stream << "\n"
+ "n_state_trellis_time_bits = " << d_n_state_trellis_time_bits << "\n";
}
- delete [] d_states[1];
- // delete the save buffer
+ // always start the fsm in the "init" state
- char** t_save_buffer = d_save_buffer;
- for (size_t n = 0; n < d_n_code_inputs; n++) {
- delete [] (*t_save_buffer++);
+ d_fsm_state = fsm_dec_viterbi_init;
+
+ if (d_do_termination == true) {
+ // create a vector of indexes to states when doing termination
+
+ d_term_states_ndx[0].resize (d_n_states);
+ d_term_states_ndx[1].resize (d_n_states);
}
- delete [] d_save_buffer;
-#endif
}
+template<typename computation_t>
void
-decoder_viterbi::reset_metrics
-(u_char which)
+decoder_viterbi<computation_t>::expand_node
+(void* in_node)
{
- 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
- }
+ if ((d_do_termination == true) &
+ (get_time (in_node) >= d_block_size_bits))
+ expand_node__term (in_node);
+ else
+ expand_node__input (in_node);
}
+template<typename computation_t>
void
-decoder_viterbi::zero_metrics
-(u_char which)
+decoder_viterbi<computation_t>::do_init
+()
{
- 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
+ if (d_do_termination == true) {
+ // reset the termination stuff
+
+ d_n_term_bits = 0;
+ d_which_term = 0;
+ d_term_ndx[0] = d_n_states;
+
+ for (memory_t m = 0; m < d_n_states; m++)
+ d_term_states_ndx[0] = m;
+
+ // FIXME: this might not be necessary; might be necessary to set
+ // just the [0] entries
+ d_term_ndx[1] = 0;
+ d_term_states_ndx[1].assign (d_n_states, 0);
}
}
+template<typename computation_t>
void
-decoder_viterbi::decode_private
+decoder_viterbi<computation_t>::decode_private
()
{
-#if 0
-
-#if DO_TIME_THOUGHPUT
struct timeval t_tp;
- start_timer (&t_tp);
-#endif
-#if DO_PRINT_DEBUG
- size_t t_state_print_bits = d_total_n_delays;
- size_t t_mem_print_bits = d_total_n_delays;
-#endif
-// setup variables for quicker access
- const char **in_buf = (const char **) &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 = compute_n_input_metrics (noutput_items);
- int t_noutput_bits = noutput_items;
+ if (DO_TIME_THOUGHPUT)
+ start_timer (&t_tp);
-#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
+ // jump to the correct state in the fsm
-// 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);
+ switch (d_fsm_state) {
+ case fsm_dec_viterbi_init:
+ if (DO_PRINT_DEBUG_FSM) {
+ std::cout << "Starting FSM Decoder Viterbi Init\n";
}
-// 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_state == fsm_dec_viterbi_init ? "init" :
- (d_fsm_state == fsm_dec_viterbi_doing_up ? "up" :
- (d_fsm_state == fsm_dec_viterbi_doing_middle ? "middle" :
- (d_fsm_state == fsm_dec_viterbi_doing_term ? "term" :
- (d_fsm_state == fsm_dec_viterbi_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_state == fsm_dec_viterbi_init ? "init" :
- (d_fsm_state == fsm_dec_viterbi_doing_up ? "up" :
- (d_fsm_state == fsm_dec_viterbi_doing_middle ? "middle" :
- (d_fsm_state == fsm_dec_viterbi_doing_term ? "term" :
- (d_fsm_state == fsm_dec_viterbi_output ? "output" : "unknown"))))) <<
"'\n";
-#endif
-// jump to the correct state in the fsm
- switch (d_fsm_state) {
- case fsm_dec_viterbi_doing_up:
-#if 0
- encode_loop_up ();
-#endif
- break;
- case (fsm_dec_viterbi_doing_middle):
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Entered fsm_dec_viterbi_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_block_size_bits != 0) &
- (d_time_count < d_block_size_bits) &
- (t_in_buf_ndx < t_ninput_items)) |
- ((d_block_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.
+ do_init ();
-// 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_block_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_block_size_bits != 0) &
- (d_time_count == d_block_size_bits)) {
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Setting FSM to fsm_dec_viterbi_doing_term\n";
-#endif
- d_fsm_state = fsm_dec_viterbi_doing_term;
- }
- break;
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Exited fsm_dec_viterbi_doing_middle\n";
-#endif
- case (fsm_dec_viterbi_doing_term):
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Entered fsm_dec_viterbi_doing_term\n";
-#endif
-// set the "next" up_down index to the end of their states
- size_t t_time_count = d_total_n_delays - (d_time_count -
d_block_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_total_n_delays - t_time_count + 1) <<
- " of " << d_total_n_delays << "; 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.
+ d_fsm_state = fsm_dec_viterbi_doing_input;
-// 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_viterbi_output\n";
-#endif
- d_fsm_state = fsm_dec_viterbi_output;
- }
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Exited fsm_dec_viterbi_doing_term\n";
-#endif
- break;
- case (fsm_dec_viterbi_output):
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Entered fsm_dec_viterbi_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
+ if (DO_PRINT_DEBUG_FSM) {
+ std::cout << "Setting state to FSM Decoder Viterbi Doing Input\n"
+ "Ending FSM Decoder Viterbi Init\n";
+ }
+ break;
-// see where the output data will terminate
- int t_next_out_buf_ndx = (t_out_buf_ndx +
- (d_block_size_bits / g_num_bits_per_byte));
- int t_next_out_bit_shift = (t_out_bit_shift +
- (d_block_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_block_size_bits << " bits == " <<
- (d_block_size_bits / g_num_bits_per_byte) << " Byte" <<
- ((d_block_size_bits / g_num_bits_per_byte) != 1 ? "s" : "") <<
- " + " << (d_block_size_bits % g_num_bits_per_byte) << " bit" <<
- ((d_block_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_total_n_delays << " bit" <<
- ((d_total_n_delays != 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_total_n_delays; 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_block_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_block_bit_ndx = d_block_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_block_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_block_size_bits / g_num_bits_per_byte) +
- ((d_block_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_block_size_bits << " bit" <<
- (d_block_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_block_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_viterbi_init\n";
-#endif
- d_fsm_state = fsm_dec_viterbi_init;
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Exited fsm_dec_viterbi_output\n";
-#endif
- break;
- case (fsm_dec_viterbi_init):
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Entered fsm_dec_viterbi_init\n";
-#endif
-// this is called immediately (first input bit upon startup),
-// or after termination of a trellis.
+ case fsm_dec_viterbi_doing_input:
+ if (DO_PRINT_DEBUG_FSM) {
+ std::cout << "Starting FSM Decoder Viterbi Doing Input\n";
+ }
-// 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_viterbi_doing_up\n";
-#endif
- d_fsm_state = fsm_dec_viterbi_doing_up;
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Exited fsm_dec_viterbi_init\n";
-#endif
- break;
-// should never get here!
- default:
- assert (0);
-// done (switch) with FSM
+
+ if (DO_PRINT_DEBUG_FSM) {
+ std::cout << "Ending FSM Decoder Viterbi Doing Input\n";
}
-// done (while) there are inputs
- }
+ break;
-// 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 blocks processed
-#if DO_PRINT_DEBUG_EXIT
- std::cout << "Exiting FSM in state: " <<
- (d_fsm_state == fsm_dec_viterbi_init ? "init" :
- (d_fsm_state == fsm_dec_viterbi_doing_up ? "up" :
- (d_fsm_state == fsm_dec_viterbi_doing_middle ? "middle" :
- (d_fsm_state == fsm_dec_viterbi_doing_term ? "term" :
- (d_fsm_state == fsm_dec_viterbi_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);
+ case (fsm_dec_viterbi_doing_term):
+ if (DO_PRINT_DEBUG_FSM) {
+ std::cout << "Starting FSM Decoder Viterbi Doing Term\n";
+ }
-// 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);
+ if (DO_PRINT_DEBUG_FSM) {
+ std::cout << "Ending FSM Decoder Viterbi Doing Term\n";
}
- 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
+ break;
+ default:
+ assert (0);
}
-#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
-}
-
#if 0
+ if (DO_TIME_THOUGHPUT) {
+ u_long d_t = end_timer (&t_tp);
-void
-decoder_viterbi::encode_loop_up ()
-{
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Starting fsm_dec_viterbi_doing_up\n";
+ 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
-
- // 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_total_n_delays) &
- (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_total_n_delays = " << d_total_n_delays << "\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_total_n_delays) {
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Setting FSM to fsm_dec_viterbi_doing_middle\n";
-#endif
- d_fsm_state = fsm_dec_viterbi_doing_middle;
- }
-#if DO_PRINT_DEBUG_FSM
- std::cout << "Exited fsm_dec_viterbi_doing_up\n";
-#endif
}
-#endif
+
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.h
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -26,181 +26,164 @@
#include "decoder.h"
#include "encoder_convolutional.h"
-#if 0
-template<typename pdf_fcn_io_t>
-class code_metrics_decoder;
+const bool G_LIBECC_DECODE_FULL = true;
+const bool G_LIBECC_DECODE_PARTIAL = false;
-template<typename pdf_fcn_io_t>
-libecc_code_metrics_create_decoder
-(code_convolutional_trellis* trellis,
- code_metrics_table<pdf_fcn_io_t>* table = 0,
- int sample_precision = 0);
-
-
- // compute all output-bit combinations of the incoming symbols' metrics
-
- void compute_all_outputs (pdf_fcn_io_t* syms, std::vector<unsigned long>&
out);
- void compute_all_outputs (pdf_fcn_io_t* syms, std::vector<float>& out);
-
- size_t d_n_code_outputs;
- std::vector<unsigned long> in_l[2];
- std::vector<float> in_f[2];
-#endif
-
+template<typename computation_t>
class decoder_viterbi : public decoder
{
public:
/*!
- * \brief Decode the incoming metrics streams using the Viterbi algorithm.
+ * \brief Decode the incoming metrics streams using the Viterbi
+ * algorithm. The actual algorithm used here is similar to the "Lazy"
+ * method: instead of expanded all nodes for each incoming set of
+ * metrics, expand only the node with the minimum metric. In the
+ * worst case ("low" SNR), all nodes will be expanded - just like the
+ * standard Viterbi algorithm. In the best case ("high" SRN), one
+ * node per set of input metrics will be expanded.
*
- * 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).
+ * NOTE: This class is not instantiated directly, but instead through
+ * a call to "libecc_decoder_viterbi_create".
*/
- decoder_viterbi (int sample_precision,
- const encoder_convolutional* l_encoder);
+ // decoder_viterbi: instantiation method
+ //
+ // encoder: the encoder which was used to create the incoming data
+ //
+ // sample_precision: incoming data are metrics with the given precision:
+ // 0 : float
+ // 1 through 8: u_int8_t
+ // 9 through 16: u_int16_t
+ // 17 through 32: u_int32_t
+ //
+ // NOTE1: Any integer precision beyond 8 or so will provide marginal
+ // benefit to the decoding algorithm in terms of lower error rate
+ // for a given SNR.
+ //
+ // NOTE2: float precision is somewhat slower than integer precision;
+ // use integer whenever possible.
+ //
+ // full_or_partial: type of decoding to perform;
+ // full decoding: requires block coding, and decodes the whole
+ // block (plus any termination bits). Requires more memory than
+ // partial block, even though there is less bookkeeping for each
+ // output bit.
+ //
+ // partial decoding: works on block or stream data, and parses
+ // only a fixed number of input time-metrics before deciding each
+ // output time-bit. Requires less memory than full block
+ // decoding, but also more bookkeeping for each output bit.
+ //
+ // n_bits_before_decode: For partial decoding only; will be ignored
+ // for full block decoding. The number of time-metrics (code output
+ // bits) to process before deciding on an output bit.
+ // 0: use 5.3 constriant-length bits
+ // otherwise: use the number of bits provided
+ //
- virtual ~decoder_viterbi ();
+ decoder_viterbi (const encoder_convolutional* encoder,
+ u_int8_t sample_precision = 10,
+ bool full_or_partial = G_LIBECC_DECODE_PARTIAL,
+ u_int32_t n_bits_before_decode = 0);
+ virtual ~decoder_viterbi () {};
+
protected:
-/*
- * 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
- */
+ // reset the state trellis; requires that
+ // "d_n_state_trellis_time_bits" be set beforehand, and depends on
+ // the exact declaration of the trellis.
- typedef struct state_t {
- struct state_t* d_connections;
- float d_max_metric;
- int d_max_state_ndx;
- int d_max_input;
- } state_t, *state_t_ptr;
+ virtual void reset_state_trellis () = 0;
-/*
- * state_get_from(v,i,k): use to retrieve a given bit-memory state,
- * from the inputs:
- *
- * memory_t v: the value from which to retrieve the given state
- * size_t i: for which input stream (0 to #I-1)
- * size_t k: the number of memory slots per input (e.g. 1+D^2 -> 2)
- */
+ // expand_node: expand the provided node
- inline memory_t state_get_from (memory_t v,
- size_t i,
- size_t k)
- {return (((v)>>((i)*(k)))&((1<<(k))-1));};
+ void expand_node (void* node);
+ virtual void expand_node__input (void* node) = 0;
+ virtual void expand_node__term (void* node) = 0;
-/*
- * state_add_to(s,v,i,k): use to create a given bit-memory state,
- * from the inputs:
- *
- * memory_t s: the state value to modify
- * memory_t v: value to set the state to for this input
- * size_t i: for which input stream (0 to #I-1)
- * size_t k: the number of memory slots per input (e.g. 1+D^2 -> 2)
- */
+ // get the relative bit-time for the given node, to check for doing
+ // termination
- inline void state_add_to (memory_t s,
- memory_t v,
- size_t i,
- size_t k)
- {(s)|=(((v)&((1<<(k))-1))<<((i)*(k)));};
+ virtual size_t get_time (void* node) = 0;
-/*
- * fsm_dec_viterbi_t: finite state machine for the Viterbi decoder
- *
- * fsm_dec_viterbi_init: initialize for a new block / 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
- */
+ // add_node: add the provided out_note to the appropriate list,
+ // given its originating in_node and metric relative to that
+ // originating node
+ virtual void add_node (void* in_node,
+ void* out_node,
+ memory_t out_bits) = 0;
+
+ // get the next time slot to work with; will vary depending on the
+ // actual implementation
+
+ virtual size_t get_next_time (size_t in_time) = 0;
+
+ // check the given node for membership in the trellis
+
+ virtual void check_node (void** in_node) = 0;
+
+ // the init routine; for when a block is finished and things need to
+ // be reset
+
+ virtual void do_init ();
+
+ // fsm_dec_viterbi_t: finite state machine for the Viterbi decoder
+ //
+ // fsm_dec_viterbi_init: initialize for a new block / block; this is
+ // already done at instantiation, so do it only at the end of a
+ // block.
+ //
+ // fsm_dec_viterbi_doing_input: working on encoded inputs
+ //
+ // fsm_dec_viterbi_doing_term: working on encoded termination bits
+
enum fsm_dec_viterbi_t {
- fsm_dec_viterbi_init, fsm_dec_viterbi_doing_up,
- fsm_dec_viterbi_doing_middle, fsm_dec_viterbi_doing_term
+ fsm_dec_viterbi_init, fsm_dec_viterbi_doing_input,
+ fsm_dec_viterbi_doing_term
};
virtual void decode_private ();
#if 0
virtual void decode_loop (size_t* which_counter, size_t how_many);
#endif
- virtual void get_next_inputs () {
- d_in_buf->read_items ((void*)(&(d_current_inputs[0])));
- d_in_buf->increment_indices ();
- };
+ virtual void get_next_inputs (size_t time_ndx = 0) = 0;
virtual void write_output_bits () {
d_out_buf->write_items ((void*)(&(d_current_outputs[0])));
d_out_buf->increment_indices ();
};
- void encode_loop_up ();
-
- virtual void update_traceback__up (size_t from_state_ndx,
- size_t to_state_ndx,
- size_t l_input) = 0;
- virtual void update_traceback__middle () = 0;
- virtual void update_traceback__term () = 0;
-
- void reset_metrics (u_char which);
- void zero_metrics (u_char which);
-
encoder_convolutional* d_encoder;
code_convolutional_trellis* d_trellis;
fsm_dec_viterbi_t d_fsm_state;
- size_t d_time_count, d_n_total_inputs_per_stream;
+ size_t d_time_count, d_total_n_inputs_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, d_total_n_delays;
- size_t d_states_ndx, d_up_term_ndx;
- bool d_do_termination;
+ size_t d_n_states, d_n_input_combinations, d_n_bits_to_term;
+ size_t d_states_ndx, d_total_n_nodes_to_alloc;
+ size_t d_n_code_outputs, d_n_code_inputs;
+ size_t d_n_state_trellis_time_bits, d_n_bits_before_decode;
+ bool d_do_termination, d_do_streaming, d_do_full_or_partial;
+
+ // for termination, need to keep around the current and next term
+ // states, so-as to be able to quicly lookup the correct inputs to
+ // terminate the trellis for the given state
+
+ u_int8_t d_which_term;
+ std::vector<memory_t> d_term_states_ndx[2];
+ size_t d_term_ndx[2];
+ size_t d_n_term_bits;
+
#if 1
- state_t_ptr d_states[2];
- size_t* d_up_term_states_ndx[2];
char **d_save_buffer;
#else
- std::vector<state_t> d_states[2];
- std::vector<size_t> d_up_term_states_ndx[2];
std::vector<char **> d_save_buffer; ???
#endif
- // "inputs" are the current input symbols as soft-floats, to be
- // converted to metrics internally
+ // "outputs" are the current output bits,
+ // in the LSB (&1) of each "u_int8_t"
- std::vector<float> d_current_inputs;
-
- // "outputs" are the current output bits, in the LSB (&1) of each "char"
-
- std::vector<char> d_current_outputs;
+ std::vector<u_int8_t> d_current_outputs;
};
#endif /* INCLUDED_DECODER_VITERBI_H */
Deleted:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.cc
Deleted:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.h
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy.cc
(rev 0)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -0,0 +1,305 @@
+/* -*- 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_lazy.h>
+#include <assert.h>
+#include <iostream>
+
+#define DO_TIME_THOUGHPUT 0
+#define DO_PRINT_DEBUG 0
+#define DO_PRINT_DEBUG_VARS 0
+#define DO_PRINT_DEBUG_FSM 0
+
+#include <mld/mld_timer.h>
+#include <mld/n2bs.h>
+
+decoder_viterbi_lazy::decoder_viterbi_lazy
+(const encoder_convolutional* encoder,
+ u_int8_t sample_precision,
+ bool full_or_partial,
+ u_int32_t n_bits_before_decode) :
+ decoder_viterbi<computation_t> (encoder,
+ sample_precision,
+ full_or_partial,
+ n_bits_before_decode)
+{
+ if (sample_precision == 0) {
+ std::cerr << "decoder_viterbi_lazy:: Error: The Lazy Viterbi Decoder "
+ " must use integer precision for the metrics.\n";
+ assert (0);
+ }
+
+ // set up the nodes
+
+ d_nodes.resize (d_total_n_nodes_to_alloc);
+
+ // set up the shadow heads ... depends on the sample precision
+
+ d_n_shadow_heads = (1 << sample_precision) * d_n_code_outputs;
+
+ // set up so that the trellis' init state contains the first node,
+ // in all the various structures
+
+ d_current_shadow_head_ndx = 0;
+ node_dll_t_ptr t_node = d_nodes.checkout ();
+ t_node->d_item.d_this_state = d_encoder->start_memory_state ();
+ add_node (0, t_node, 0);
+}
+
+void
+decoder_viterbi_lazy::reset_state_trellis
+()
+{
+ // reset the state trellis structures
+
+ // resize the first dimension (time)
+
+ d_state_trellis.resize (d_n_state_trellis_time_bits);
+
+ // resize all second dimensions (# of states)
+
+ for (size_t m = 0; m < d_n_state_trellis_time_bits; m++)
+ d_state_trellis[m].resize (d_n_states);
+}
+
+void
+decoder_viterbi_lazy::expand_node__input
+(void* node)
+{
+ // given the input node, expand it out per the trellis
+
+ node_dll_t_ptr in_node_dll = (node_dll_t_ptr) node;
+ node_t_ptr in_node = &(in_node_dll->d_item);
+ memory_t in_state = in_node->d_this_state;
+ size_t in_time = in_node->d_this_time;
+ size_t out_time = get_next_time (in_time);
+
+ for (memory_t m = 0; m < d_n_input_combinations; m++) {
+ // get an unused node to add
+
+ node_dll_t_ptr t_add_node_dll = d_nodes.checkout ();
+ node_t_ptr t_add_node = &(t_add_node_dll->d_item);
+
+ // and set it's variables
+
+ t_add_node->d_previous_node = in_node;
+ t_add_node->d_inputs = m;
+ t_add_node->d_this_state = in_state; // this will be updated by the lookup
+ t_add_node->d_this_time = out_time;
+
+ // using the trellis, find the output state and bits
+
+ memory_t out_bits = 0;
+ d_trellis->encode_lookup (t_add_node->d_this_state,
+ (const memory_t) m, out_bits);
+
+ // add the new node to the trellis or shadow list, with the
+ // relative metric provided by its branch
+
+ add_node (node, (void*) t_add_node_dll, out_bits);
+ }
+}
+
+void
+decoder_viterbi_lazy::expand_node__term
+(void* node)
+{
+ // given the input node, expand it out per the trellis
+
+ node_dll_t_ptr in_node_dll = (node_dll_t_ptr) node;
+ node_t_ptr in_node = &(in_node_dll->d_item);
+ memory_t in_state = in_node->d_this_state;
+ size_t in_time = in_node->d_this_time;
+ size_t out_time = get_next_time (in_time);
+
+ // get an unused node to add
+
+ node_dll_t_ptr t_add_node_dll = d_nodes.checkout ();
+ node_t_ptr t_add_node = &(t_add_node_dll->d_item);
+
+ // and set it's variables
+
+ t_add_node->d_previous_node = in_node;
+ t_add_node->d_this_state = in_state; // this will be updated by the lookup
+ t_add_node->d_this_time = out_time;
+
+ // get the termination inputs for this state and term bit #
+
+ memory_t term_start_state = d_term_states_ndx[d_which_term][in_state];
+ memory_t t_term_inputs = t_add_node->d_inputs =
+ d_trellis->get_termination_inputs (term_start_state, d_n_term_bits);
+
+ // using the trellis, find the output state and bits
+
+ memory_t out_bits = 0;
+ d_trellis->encode_lookup (term_start_state,
+ (const memory_t) t_term_inputs,
+ out_bits);
+
+ // add the new node to the trellis or shadow list, with the
+ // relative metric provided by its branch
+
+ add_node (node, (void*) t_add_node_dll, out_bits);
+}
+
+void
+decoder_viterbi_lazy::add_node
+(void* in_node,
+ void* out_node,
+ memory_t out_bits)
+{
+ // add the provided note to the trellis or shadow list, as
+ // appropriate for the particular implementation: for the standard
+ // viterbi decoder, this means the trellis.
+
+ size_t relative_metric = 0;
+
+ if (in_node) {
+ node_dll_t_ptr in_node_dll = (node_dll_t_ptr) in_node;
+ size_t in_time = in_node_dll->d_item.d_this_time;
+
+ // metrics are relative to the current shadow head index
+
+ relative_metric = (size_t) d_branch_metrics[in_time][out_bits];
+ }
+
+ size_t which_head = d_current_shadow_head_ndx + relative_metric;
+
+ // wrap around if necessary
+
+ if (which_head >= d_n_shadow_heads)
+ which_head -= d_n_shadow_heads;
+
+ // add to the computed shadow head's list
+
+ shadow_head_t& t_head = d_shadow_heads[which_head];
+ shadow_node_dll_t_ptr t_shadow_node_dll = d_shadow_nodes.checkout ();
+ shadow_node_t_ptr t_list_node = &(t_shadow_node_dll->d_item);
+ t_list_node->d_node = (node_dll_t_ptr) out_node;
+
+ if ((t_head.d_n_items)++ == 0) {
+ // nothing in this list yet; start it
+ t_head.d_head = t_head.d_tail = t_shadow_node_dll;
+ } else {
+ // list is active; add to the tail
+ t_head.d_tail->d_next = t_shadow_node_dll;
+ t_head.d_tail = t_shadow_node_dll;
+ }
+}
+
+void
+decoder_viterbi_lazy::check_node
+(void** node)
+{
+ node_dll_t_ptr in_node_dll = (node_dll_t_ptr)(*node);
+ node_t_ptr in_node = &(in_node_dll->d_item);
+
+ // check to see if this node's slot is already occupied
+
+ if (d_state_trellis[in_node->d_this_time][in_node->d_this_state] == 0) {
+
+ // no: then fill it, and return this node
+
+ d_state_trellis[in_node->d_this_time][in_node->d_this_state] =
+ in_node;
+
+ } else {
+
+ // yes: release this node from use; make it available for re-use
+
+ d_nodes.release (in_node_dll);
+
+ // reset the (referenced) pointer to 0
+
+ *node = 0;
+ }
+}
+
+void
+decoder_viterbi_lazy::do_init
+()
+{
+ decoder_viterbi<computation_t>::do_init ();
+
+ // reset the nodes, shadow heads, trellis
+
+ reset_shadow_nodes ();
+ d_nodes.reset ();
+ reset_state_trellis ();
+
+ // reset the max time index
+
+ d_max_time_ndx = 0;
+}
+
+node_dll_t_ptr
+decoder_viterbi_lazy::find_minimum_metric_node
+()
+{
+ // start with the current shadow head index, looking for any non-0
+ // heads in the shadow_heads list; wrap around as needed since the
+ // list is relative to the current head index. When a non-0 entry
+ // is found, pop off the head, then check to make sure it's valid.
+
+ node_dll_t_ptr node_dll = 0;
+
+ while (node_dll == 0) {
+
+ // find the next used shadow head
+
+ while (d_shadow_heads[d_current_shadow_head_ndx].d_head == 0)
+ if (++d_current_shadow_head_ndx > d_n_shadow_heads)
+ d_current_shadow_head_ndx = 0;
+
+ // get the head, list node, and node
+
+ shadow_head_t& t_head = d_shadow_heads[d_current_shadow_head_ndx];
+ shadow_node_dll_t_ptr list_node_dll = t_head.d_head;
+ shadow_node_t_ptr list_node = &(list_node_dll->d_item);
+ node_dll = list_node->d_node;
+
+ // remove this shadow node from this head
+
+ if (--(t_head.d_n_items) == 0) {
+ // only item; 0 everything
+ t_head.d_head = t_head.d_tail = 0;
+ } else {
+ // more than one item; reset the head to the next item
+ t_head.d_head = list_node_dll->d_item.d_next;
+ list_node_dll->d_item.d_next = 0;
+ }
+
+ // release the shadow DLL enclosure for reuse
+
+ d_shadow_nodes.release (list_node_dll);
+
+ // check the node for membership in the trellis
+
+ check_node ((void**)(&node_dll));
+ }
+
+ return (node_dll);
+}
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy.h
(rev 0)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -0,0 +1,215 @@
+/* -*- 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_LAZY_H
+#define INCLUDED_DECODER_VITERBI_LAZY_H
+
+#include "decoder_viterbi.h"
+#include "doubly_linked_list.h"
+
+typedef unsigned long computation_t;
+
+// a node is an element in the state trellis, which gets compared
+// with on each iteration of inputs it contains the current best
+// metric for this node, as well as the state and inputs which
+// achieved this best metric. This single structure handles
+// everything, from keeping the computed metrics to the (basic)
+// traceback. For partial decoding, YA structure is desired to do
+// accounting for how many current paths are in each time slot and such.
+
+typedef struct node {
+ struct node* d_previous_node;
+ memory_t d_inputs;
+ memory_t d_this_state;
+ size_t d_this_time;
+} node_t, *node_t_ptr;
+
+typedef struct dll<node_t> node_dll_t, *node_dll_t_ptr;
+
+class decoder_viterbi_lazy : public decoder_viterbi<computation_t>
+{
+public:
+/*!
+ * \brief Decode the incoming metrics streams using the Viterbi
+ * algorithm. The actual algorithm used here is the "Lazy" method:
+ * instead of expanded all nodes for each incoming set of metrics,
+ * expand only the node with the minimum metric. In the worst case
+ * ("low" SNR), all nodes will be expanded - just like the standard
+ * Viterbi algorithm. In the best case ("high" SRN), one node per set
+ * of input metrics will be expanded.
+ *
+ * Note that the Lazy method requires the use of integer metrics.
+ */
+
+ // decoder_viterbi_lazy: instantiation method
+ //
+ // encoder: the encoder which was used to create the incoming data
+ //
+ // sample_precision: incoming data are metrics with the given precision:
+ // 1 through 8: u_int8_t
+ // 9 through 16: u_int16_t
+ // 17 through 32: u_int32_t
+ //
+ // NOTE: Any integer precision beyond 8 or so will provide marginal
+ // benefit to the decoding algorithm in terms of lower error rate
+ // for a given SNR.
+ //
+ // full_or_partial: type of decoding to perform;
+ // full decoding: requires block coding, and decodes the whole
+ // block (plus any termination bits). Requires more memory than
+ // partial block, even though there is less bookkeeping for each
+ // output bit.
+ //
+ // partial decoding: works on block or stream data, and parses
+ // only a fixed number of input time-metrics before deciding each
+ // output time-bit. Requires less memory than full block
+ // decoding, but also more bookkeeping for each output bit.
+ //
+ // n_bits_before_decode: For partial decoding only; will be ignored
+ // for full block decoding. The number of time-metrics (code output
+ // bits) to process before deciding on an output bit.
+ // 0: use 5.3 constriant-length bits
+ // otherwise: use the number of bits provided
+ //
+
+ decoder_viterbi_lazy (const encoder_convolutional* encoder,
+ u_int8_t sample_precision = 10,
+ bool full_or_partial = G_LIBECC_DECODE_PARTIAL,
+ u_int32_t n_bits_before_decode = 0);
+
+ virtual ~decoder_viterbi_lazy () {};
+
+protected:
+ // the state trellis is a two dimensional "matrix", where the first
+ // dimension is the "time", and the second is a state node entry.
+
+ std::vector<std::vector<node_t_ptr> > d_state_trellis;
+
+ doubly_linked_list<node_t> d_nodes;
+
+ // a shadow_node is a doubly linked list of the current nodes which
+ // have not been accepted into the actual state trellis structure.
+
+ struct shadow_node;
+ doubly_linked_list<struct shadow_node> d_shadow_nodes;
+ typedef struct dll<struct shadow_node> shadow_node_dll_t,
+ *shadow_node_dll_t_ptr;
+
+ typedef struct shadow_node {
+ shadow_node_dll_t_ptr d_next;
+ node_dll_t_ptr d_node;
+ } shadow_node_t, *shadow_node_t_ptr;
+
+ // the shadow_head contains the head and tail of the linked list of
+ // shadow_node's, in order to quickly find and move items around.
+
+ typedef struct shadow_head {
+ shadow_node_dll_t_ptr d_head, d_tail;
+ size_t d_n_items;
+ } shadow_head_t, *shadow_head_t_ptr;
+
+ std::vector<shadow_head_t> d_shadow_heads;
+
+ // "branch_metrics" are the converted metrics for each branch,
+ // ordered as a two dimensional "matrix". The first dimension is
+ // "time", and the second is the combined output number. The first
+ // dimension varies depending on which type of processing is taking
+ // place: full or partial. For the former, there need to be
+ // (d_block_size_bits + any termination bit) # of time entries. For
+ // the latter, the user defines how many time bits to keep. All of
+ // these branch metrics must be kept around because of the way in
+ // which the "lazy" style Viterbi decoder jumps back and forth in time.
+
+ std::vector<std::vector<computation_t> > d_branch_metrics;
+
+ // reset_shadow_nodes: reset (or setup, same difference) the shadow
+ // nodes for the desired # of pre-allocated list items as found in
+ // d_n_shadow_heads.
+
+ inline void reset_shadow_nodes ()
+ {d_shadow_heads.resize (d_n_shadow_heads);};
+
+ // find_minimum_metric_node: find the minimum metric node; this can
+ // be implemented differently for other decoding methods
+
+ node_dll_t_ptr find_minimum_metric_node ();
+
+ // reset the state trellis; requires that
+ // "d_n_state_trellis_time_bits" be set beforehand, and depends on
+ // the exact declaration of the trellis.
+
+ virtual void reset_state_trellis ();
+
+ // expand_node: expand the provided node, for where the given
+ // to-be-encoded bits came from (input or termination)
+
+ virtual void expand_node__input (void* node);
+ virtual void expand_node__term (void* node);
+
+ // get the relative bit-time for the given node,
+ // to check for doing termination
+
+ inline virtual size_t get_time (void* node) {
+ node_dll_t_ptr node_dll = (node_dll_t_ptr) node;
+ return (node_dll->d_item.d_this_time);
+ };
+
+ // add_node: add the provided out_note to the appropriate list,
+ // given its originating in_node and metric relative to that
+ // originating node
+
+ virtual void add_node (void* in_node,
+ void* out_node,
+ memory_t out_bits);
+
+ // get the next time slot to work with; must check for loop-around
+ // for partial decoding
+
+ inline virtual size_t get_next_time (size_t in_time) {
+ if (++in_time > d_n_state_trellis_time_bits)
+ in_time = 0;
+ return (in_time);
+ };
+
+ // check the given node for membership in the trellis
+
+ virtual void check_node (void** in_node);
+
+ // the init routine; for when a block is finished and things need to
+ // be reset
+
+ virtual void do_init ();
+
+ // get the next inputs; for the lazy method, those are stored
+
+ virtual void get_next_inputs (size_t time_ndx = 0) {
+ if (time_ndx <= d_max_time_ndx)
+ return;
+ d_in_buf->read_items ((void*)(&(d_branch_metrics[time_ndx])));
+ d_in_buf->increment_indices ();
+ };
+
+ size_t d_max_time_ndx, d_n_shadow_heads;
+ size_t d_current_shadow_head_ndx;
+};
+
+#endif /* INCLUDED_DECODER_VITERBI_LAZY_H */
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy_alt.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy_alt.cc
(rev 0)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_lazy_alt.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -0,0 +1,97 @@
+/* -*- 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_lazy_alt.h>
+#include <assert.h>
+#include <iostream>
+
+#define DO_PRINT_DEBUG 0
+
+#include <mld/n2bs.h>
+
+decoder_viterbi_lazy_alt::decoder_viterbi_lazy_alt
+(const encoder_convolutional* encoder,
+ u_int8_t sample_precision,
+ bool full_or_partial,
+ u_int32_t n_bits_before_decode) :
+ decoder_viterbi_lazy (encoder,
+ sample_precision,
+ full_or_partial,
+ n_bits_before_decode)
+{
+ d_is_shadow.resize ();
+}
+
+void
+decoder_viterbi_lazy_alt::do_init
+()
+{
+ // do the inherited init
+
+ decoder_viterbi_lazy::do_init ();
+
+ // set all of the trellis nodes "is_shadow" to false
+
+ for (size_t m = 0; m < d_n_state_trellis_time_bits; m++)
+ d_is_shadow[m].assign (d_n_states, true);
+}
+
+void
+decoder_viterbi_lazy::add_node
+(void* node,
+ computation_t relative_metric)
+{
+ node_dll_t_ptr in_node_dll = (node_dll_t_ptr) node;
+ node_t_ptr in_node = in_node_dll->d_item;
+
+ // check to see if this node is a shadow node or not
+
+ if (d_is_shadow[in_node->d_this_time][in_node->d_this_state] == false) {
+ // node has already been accepted as a minimum; ignore the provided node
+
+ d_nodes.release (in_node_dll);
+
+ // reset the (referenced) pointer to 0
+
+ node = 0;
+ } else {
+
+
+ }
+}
+
+void
+decoder_viterbi_lazy_alt::check_node
+(void*& node)
+{
+ node_dll_t_ptr in_node_dll = (node_dll_t_ptr) node;
+ node_t_ptr in_node = in_node_dll->d_item;
+
+ // node is already in place;
+ // just set its "is_shadow" property to false
+
+ d_is_shadow[in_node->d_this_time][in_node->d_this_state] = false;
+}
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_standard.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_standard.cc
(rev 0)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_standard.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -0,0 +1,14 @@
+template<typename computation_t>
+void
+decoder_viterbi<computation_t>::add_node
+(node_dll_t_ptr node,
+ memory_t out_bits)
+{
+ // add the provided note to the trellis or shadow list, as
+ // appropriate for the particular implementation: for the standard
+ // viterbi decoder, this means the trellis.
+
+ computation_t relative_metric = d_branch_metrics[out_bits];
+
+
+}
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_standard.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_standard.h
(rev 0)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_standard.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -0,0 +1,145 @@
+/* -*- 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_STANDARD_H
+#define INCLUDED_DECODER_VITERBI_STANDARD_H
+
+#include "decoder_viterbi.h"
+
+template<typename computation_t>
+class decoder_viterbi : public decoder
+{
+public:
+/*!
+ * \brief Decode the incoming metrics streams using the Viterbi
+ * algorithm. The actual algorithm used here is similar to the "Lazy"
+ * method: instead of expanded all nodes for each incoming set of
+ * metrics, expand only the node with the minimum metric. In the
+ * worst case ("low" SNR), all nodes will be expanded - just like the
+ * standard Viterbi algorithm. In the best case ("high" SRN), one
+ * node per set of input metrics will be expanded.
+ *
+ * NOTE: This class is not instantiated directly, but instead through
+ * a call to "libecc_decoder_viterbi_create".
+ */
+
+ // decoder_viterbi: instantiation method
+ //
+ // encoder: the encoder which was used to create the incoming data
+ //
+ // sample_precision: incoming data are metrics with the given precision:
+ // 0 : float
+ // 1 through 8: u_int8_t
+ // 9 through 16: u_int16_t
+ // 17 through 32: u_int32_t
+ //
+ // NOTE1: Any integer precision beyond 8 or so will provide marginal
+ // benefit to the decoding algorithm in terms of lower error rate
+ // for a given SNR.
+ //
+ // NOTE2: float precision is somewhat slower than integer precision;
+ // use integer whenever possible.
+ //
+ // full_or_partial: type of decoding to perform;
+ // full decoding: requires block coding, and decodes the whole
+ // block (plus any termination bits). Requires more memory than
+ // partial block, even though there is less bookkeeping for each
+ // output bit.
+ //
+ // partial decoding: works on block or stream data, and parses
+ // only a fixed number of input time-metrics before deciding each
+ // output time-bit. Requires less memory than full block
+ // decoding, but also more bookkeeping for each output bit.
+ //
+ // n_bits_before_decode: For partial decoding only; will be ignored
+ // for full block decoding. The number of time-metrics (code output
+ // bits) to process before deciding on an output bit.
+ // 0: use 5.3 constriant-length bits
+ // otherwise: use the number of bits provided
+ //
+
+ decoder_viterbi (const encoder_convolutional* encoder,
+ u_int8_t sample_precision = 10,
+ bool full_or_partial = G_LIBECC_DECODE_PARTIAL,
+ u_int32_t n_bits_before_decode = 0);
+
+ virtual ~decoder_viterbi () {};
+
+protected:
+ // a node is an element in the state trellis, which gets compared
+ // with on each iteration of inputs it contains the current best
+ // metric for this node, as well as the state and inputs which
+ // achieved this best metric. This single structure handles
+ // everything, from keeping the computed metrics to the (basic)
+ // traceback. For partial decoding, YA structure is desired to do
+ // accounting for how many current paths are in each time slot and such.
+
+ typedef struct node {
+ struct node* d_previous_node;
+ computation_t d_metric;
+ memory_t d_inputs;
+ } node_t, *node_t_ptr;
+
+ // the state trellis is a two dimensional "matrix", where the first
+ // dimension is the "time", and the second is a state node entry.
+
+ std::vector<std::vector<node_t> > d_state_trellis;
+
+ // "branch_metrics" are the converted metrics for each branch for a
+ // given bit-time period.
+
+ std::vector<computation_t> d_branch_metrics;
+
+ // find_minimum_metric_node: find the minimum metric node; this can
+ // be implemented differently for other decoding methods
+
+ node_dll_t_ptr find_minimum_metric_node ();
+
+ // expand_node: expand the starting node referred to by the pair
+ // (bit_time, start_state_ndx), given the branch metrics for that
+ // bit_time.
+
+ void expand_node (node_dll_t_ptr in_node_dll);
+ void expand_node__input (node_dll_t_ptr in_node_dll);
+ void expand_node__term (node_dll_t_ptr in_node_dll);
+
+ // add_node: add the provided note to the trellis or shadow list, as
+ // appropriate for the particular implementation
+
+ virtual void add_node (node_dll_t_ptr in_node_dll,
+ computation_t relative_metric);
+
+ // reset the state trellis; requires that
+ // "d_n_state_trellis_time_bits" be set beforehand.
+
+ void reset_state_trellis ();
+
+ // get the next time slot to work with
+
+ virtual size_t get_next_time (size_t in_time);
+
+ // check the given node for membership in the trellis
+
+ virtual void check_node (node_dll_t_ptr& node_dll);
+};
+
+#endif /* INCLUDED_DECODER_VITERBI_STANDARD_H */
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/doubly_linked_list.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/doubly_linked_list.h
(rev 0)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/doubly_linked_list.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -0,0 +1,123 @@
+/* -*- 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_DOUBLY_LINKED_LIST_H
+#define INCLUDED_DOUBLY_LINKED_LIST_H
+
+#include <assert.h>
+#include <iostream>
+
+template<typename item_t>
+struct dll {
+ struct dll* d_next;
+ struct dll* d_prev;
+ item_t d_item;
+};
+
+template<typename item_t>
+class doubly_linked_list
+{
+public:
+ typedef struct dll<item_t> dll_t, *dll_t_ptr;
+
+ inline doubly_linked_list () {};
+
+ inline ~doubly_linked_list () {
+ d_items.resize (0);
+ };
+
+ inline size_t n_in_use () {return (d_n_in_use);};
+ inline size_t n_available () {return (d_n_available);};
+ inline void reset () {resize (d_n_alloced);};
+
+ dll_t_ptr checkout () {
+ if (d_n_available == 0) {
+ std::cerr << "doubly_linked_list::checkout: Error: "
+ "no more items available.\n";
+ assert (0);
+ }
+ d_n_in_use++;
+ dll_t_ptr t_node = d_items_available;
+ if (--d_n_available == 0) {
+ d_items_available = 0;
+ } else {
+ dll_t_ptr t_next = t_node->d_next;
+ dll_t_ptr t_prev = t_node->d_prev;
+ t_next->d_prev = t_prev;
+ t_prev->d_next = t_next;
+ }
+ if (d_items_in_use == 0) {
+ d_items_in_use = t_node->d_prev = t_node->d_next = t_node;
+ } else {
+ dll_t_ptr t_next = t_node->d_next = d_items_in_use->d_next;
+ dll_t_ptr t_prev = t_node->d_prev = d_items_in_use->d_prev;
+ t_prev->d_next = t_next->d_prev = t_node;
+ }
+ return (t_node);
+ };
+
+ void release (dll_t_ptr t_node) {
+ if (d_n_in_use == d_n_alloced)
+ return;
+ d_n_available++;
+ if (--d_n_in_use == 0) {
+ d_items_in_use = 0;
+ } else {
+ dll_t_ptr t_next = t_node->d_next;
+ dll_t_ptr t_prev = t_node->d_prev;
+ t_next->d_prev = t_prev;
+ t_prev->d_next = t_next;
+ }
+ if (d_items_available == 0) {
+ d_items_available = t_node->d_prev = t_node->d_next = t_node;
+ } else {
+ dll_t_ptr t_next = t_node->d_next = d_items_available->d_next;
+ dll_t_ptr t_prev = t_node->d_prev = d_items_available->d_prev;
+ t_prev->d_next = t_next->d_prev = t_node;
+ }
+ };
+
+ inline dll_t& operator[] (size_t n) {return (d_items[n]);};
+
+ void resize (size_t n_to_alloc) {
+ d_items.resize (n_to_alloc);
+ d_n_alloced = d_n_available = n_to_alloc;
+ d_n_in_use = 0;
+ d_items_in_use = 0;
+ dll_t_ptr current = d_items_available = &(d_items[0]);
+ for (size_t m = 1; m < d_n_alloced; m++) {
+ dll_t_ptr next = &(d_items[m]);
+ current->d_next = next;
+ next->d_prev = current;
+ }
+ d_items_available->d_prev = current;
+ current->d_next = d_items_available;
+ };
+
+protected:
+ size_t d_n_alloced, d_n_in_use, d_n_available;
+ std::vector<dll_t> d_items;
+ dll_t_ptr d_items_in_use;
+ dll_t_ptr d_items_available;
+};
+
+#endif /* INCLUDED_DOUBLY_LINKED_LIST_H */
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.cc
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -94,7 +94,7 @@
start_memory_state &= t_mask;
}
- d_init_state = start_memory_state;
+ d_start_memory_state = start_memory_state;
// reset the inputs and outputs, both to get the correct size() and
// for the sake of zeroing them out.
@@ -133,7 +133,7 @@
// copy the init states to the current memory
- d_memory = d_init_state;
+ d_memory = d_start_memory_state;
// if not doing streaming, things to do; else nothing more do
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.h
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.h
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.h
2006-08-21 16:48:00 UTC (rev 3362)
@@ -159,6 +159,9 @@
inline const size_t total_n_delays () {return (d_total_n_delays);};
inline const size_t n_bits_to_term () {return (d_n_bits_to_term);};
inline const code_convolutional_trellis* trellis() {return (d_trellis);};
+ inline const memory_t start_memory_state () {return (d_start_memory_state);};
+ inline const memory_t end_memory_state () {
+ return (d_trellis->end_memory_state());};
protected:
/*
@@ -262,10 +265,10 @@
code_convolutional_trellis* d_trellis;
- // "init_states" are the user-provided init states,
- // interpreted w/r.t. the actual trellis;
+ // "start_memory_state" is the user-provided starting memory
+ // state, interpreted w/r.t. the actual trellis;
- memory_t d_init_state;
+ memory_t d_start_memory_state;
// "term_state" is the ending state before termination, used by the
// trellis to determine the correct input-bit sequences needed to
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.cc
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.cc
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.cc
2006-08-21 16:48:00 UTC (rev 3362)
@@ -270,7 +270,7 @@
// start state is 0, same feedback, no termination
const static int t2_code_generator[] = {1, 0, 0, 1, 5, 6};
-const static size_t t2_code_feedback[] = {0, 0, 0, 0, 7, 7};
+const static int t2_code_feedback[] = {0, 0, 0, 0, 7, 7};
const static int t2_encode_soai = 1;
const static char t2_in_0[] =
@@ -1285,7 +1285,7 @@
// start state is 0, same feedback, no termination
const static int t25_code_generator[] = {1, 0, 0, 1, 5, 6};
-const static size_t t25_code_feedback[] = {0, 0, 0, 0, 7, 7};
+const static int t25_code_feedback[] = {0, 0, 0, 0, 7, 7};
const static int t25_encode_soai = 1;
const static char t25_in_0[] =
Deleted:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/lib/qa_ecc.py
Modified:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/Makefile.am
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/Makefile.am
2006-08-21 01:02:37 UTC (rev 3361)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/Makefile.am
2006-08-21 16:48:00 UTC (rev 3362)
@@ -23,8 +23,7 @@
EXTRA_DIST = run_tests.in
-# Disable qa checks due to non-standard directory structure (eb)
-# TESTS = run_tests
+TESTS = run_tests
noinst_PYTHON = qa_test_coding_1.py qa_test_coding_2.py
Added:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_ecc.py
===================================================================
---
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_ecc.py
(rev 0)
+++
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_ecc.py
2006-08-21 16:48:00 UTC (rev 3362)
@@ -0,0 +1,42 @@
+#!/usr/bin/env python
+#
+# 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.
+#
+
+from gnuradio import gr, gr_unittest
+# the local library must be imported from local directory so that make
+# check can run before installation
+import ecc
+
+class qa_ecc (gr_unittest.TestCase):
+
+ def setUp (self):
+ self.fg = gr.flow_graph ()
+
+ def tearDown (self):
+ self.fg = None
+
+ def test_000_nop (self):
+ """Just see if we can import the module...
+ They may not have drivers, etc. Don't try to run anything"""
+ pass
+
+if __name__ == '__main__':
+ gr_unittest.main ()
Property changes on:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_ecc.py
___________________________________________________________________
Name: svn:executable
+ *
Deleted:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_test_coding_1.py
Deleted:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_test_coding_2.py
Deleted:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_test_encoder_convolutional_1.py
Deleted:
gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src/python/qa_test_encoder_convolutional_2.py
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r3362 - in gnuradio/branches/developers/michaelld/wip/gr-error-correcting-codes/src: lib lib/libecc lib/libecc/tests python,
michaelld <=