From c5b588b8f182374d83918d810e6c59b3bd804d7e Mon Sep 17 00:00:00 2001 From: jcorgan Date: Fri, 4 Aug 2006 16:07:06 +0000 Subject: Merge CVS changes from FIRST_MIGRATION_2006_07_26 into trunk. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3138 221aa14e-8319-0410-a670-987f0aec2ac5 --- gr-error-correcting-codes/src/lib/Makefile.am | 36 +- gr-error-correcting-codes/src/lib/ecc.i | 16 +- .../lib/ecc_metrics_decode_viterbi_full_block.cc | 245 +++++++++ .../lib/ecc_metrics_decode_viterbi_full_block.h | 165 ++++++ .../lib/ecc_metrics_decode_viterbi_full_block.i | 77 +++ .../src/lib/ecc_streams_encode_convolutional.cc | 208 ++++++++ .../src/lib/ecc_streams_encode_convolutional.h | 158 ++++++ .../src/lib/ecc_streams_encode_convolutional.i | 77 +++ .../src/lib/ecc_streams_encode_turbo.cc | 197 +++++++ .../src/lib/ecc_streams_encode_turbo.h | 107 ++++ .../src/lib/ecc_streams_encode_turbo.i | 41 ++ .../src/lib/ecc_syms_to_metrics.cc | 150 ++++++ .../src/lib/ecc_syms_to_metrics.h | 124 +++++ .../src/lib/ecc_syms_to_metrics.i | 41 ++ .../lib/gr_metrics_decode_viterbi_full_block.cc | 228 -------- .../src/lib/gr_metrics_decode_viterbi_full_block.h | 163 ------ .../src/lib/gr_metrics_decode_viterbi_full_block.i | 77 --- .../src/lib/gr_streams_encode_convolutional.cc | 220 -------- .../src/lib/gr_streams_encode_convolutional.h | 155 ------ .../src/lib/gr_streams_encode_convolutional.i | 77 --- .../src/lib/gr_streams_encode_turbo.cc | 209 -------- .../src/lib/gr_streams_encode_turbo.h | 104 ---- .../src/lib/gr_streams_encode_turbo.i | 41 -- .../src/lib/gr_syms_to_metrics.cc | 167 ------ .../src/lib/gr_syms_to_metrics.h | 121 ----- .../src/lib/gr_syms_to_metrics.i | 41 -- .../src/lib/libecc/Makefile.am | 14 +- .../src/lib/libecc/code_convolutional_trellis.cc | 78 ++- .../src/lib/libecc/code_convolutional_trellis.h | 25 +- .../src/lib/libecc/code_io.cc | 33 ++ gr-error-correcting-codes/src/lib/libecc/code_io.h | 556 +++++++++++++++++++ .../src/lib/libecc/code_metrics.cc | 588 ++++++++++----------- .../src/lib/libecc/code_metrics.h | 213 ++++---- .../src/lib/libecc/decoder.cc | 161 ++++-- gr-error-correcting-codes/src/lib/libecc/decoder.h | 70 ++- .../src/lib/libecc/decoder_viterbi.cc | 383 +++++++------- .../src/lib/libecc/decoder_viterbi.h | 74 ++- .../src/lib/libecc/decoder_viterbi_full_block.cc | 17 +- .../src/lib/libecc/decoder_viterbi_full_block.h | 9 +- .../libecc/decoder_viterbi_full_block_i1_ic1.cc | 162 ------ .../lib/libecc/decoder_viterbi_full_block_i1_ic1.h | 66 --- .../src/lib/libecc/encoder.cc | 137 ++++- gr-error-correcting-codes/src/lib/libecc/encoder.h | 60 ++- .../src/lib/libecc/encoder_convolutional.cc | 155 ++++-- .../src/lib/libecc/encoder_convolutional.h | 67 ++- .../lib/libecc/encoder_convolutional_ic1_ic1.cc | 188 ------- .../src/lib/libecc/encoder_convolutional_ic1_ic1.h | 91 ---- .../lib/libecc/encoder_convolutional_ic8_ic8.cc | 224 -------- .../src/lib/libecc/encoder_convolutional_ic8_ic8.h | 96 ---- .../src/lib/libecc/encoder_turbo.cc | 73 ++- .../src/lib/libecc/encoder_turbo.h | 52 +- .../src/lib/libecc/mld/Makefile.am | 2 +- .../src/lib/libecc/mld/n2bs.cc | 72 ++- .../src/lib/libecc/mld/n2bs.h | 31 +- .../src/lib/libecc/tests/Makefile.am | 3 +- .../tests/qa_encoder_convolutional_ic1_ic1.cc | 84 +-- .../tests/qa_encoder_convolutional_ic1_ic1.h | 4 +- 57 files changed, 3563 insertions(+), 3470 deletions(-) create mode 100644 gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.cc create mode 100644 gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.h create mode 100644 gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.i create mode 100644 gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.cc create mode 100644 gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.h create mode 100644 gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.i create mode 100644 gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.cc create mode 100644 gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.h create mode 100644 gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.i create mode 100644 gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc create mode 100644 gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.h create mode 100644 gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.i delete mode 100644 gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.cc delete mode 100644 gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.h delete mode 100644 gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.i delete mode 100644 gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.cc delete mode 100644 gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.h delete mode 100644 gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.i delete mode 100644 gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.cc delete mode 100644 gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.h delete mode 100644 gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.i delete mode 100644 gr-error-correcting-codes/src/lib/gr_syms_to_metrics.cc delete mode 100644 gr-error-correcting-codes/src/lib/gr_syms_to_metrics.h delete mode 100644 gr-error-correcting-codes/src/lib/gr_syms_to_metrics.i create mode 100644 gr-error-correcting-codes/src/lib/libecc/code_io.cc create mode 100644 gr-error-correcting-codes/src/lib/libecc/code_io.h delete mode 100644 gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block_i1_ic1.cc delete mode 100644 gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block_i1_ic1.h delete mode 100644 gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic1_ic1.cc delete mode 100644 gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic1_ic1.h delete mode 100644 gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic8_ic8.cc delete mode 100644 gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic8_ic8.h (limited to 'gr-error-correcting-codes/src/lib') diff --git a/gr-error-correcting-codes/src/lib/Makefile.am b/gr-error-correcting-codes/src/lib/Makefile.am index 3168a58f4..602c560a0 100644 --- a/gr-error-correcting-codes/src/lib/Makefile.am +++ b/gr-error-correcting-codes/src/lib/Makefile.am @@ -23,8 +23,6 @@ include $(top_srcdir)/Makefile.common SUBDIRS = libecc -LIBS += $(GNURADIO_CORE_LIBS) - # Install this stuff so that it ends up as the gnuradio.und module # This usually ends up at: # ${prefix}/lib/python${python_version}/site-packages/gnuradio @@ -32,10 +30,9 @@ LIBS += $(GNURADIO_CORE_LIBS) ourpythondir = $(grpythondir) ourlibdir = $(grpythondir) -INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(GNURADIO_INCLUDES) +INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) -SWIGCPPPYTHONARGS = -fvirtual -python -modern $(PYTHON_CPPFLAGS) \ - $(GNURADIO_INCLUDES) +SWIGCPPPYTHONARGS = -fvirtual -python -modern $(PYTHON_CPPFLAGS) $(STD_DEFINES_AND_INCLUDES) ALL_IFILES = \ $(LOCAL_IFILES) \ @@ -45,10 +42,10 @@ NON_LOCAL_IFILES = \ $(top_srcdir)/gnuradio-core/src/lib/swig/gnuradio.i LOCAL_IFILES = \ - gr_syms_to_metrics.i \ - gr_metrics_decode_viterbi_full_block.i \ - gr_streams_encode_convolutional.i \ - gr_streams_encode_turbo.i \ + ecc_syms_to_metrics.i \ + ecc_metrics_decode_viterbi_full_block.i \ + ecc_streams_encode_convolutional.i \ + ecc_streams_encode_turbo.i \ ecc.i # These files are built by SWIG. The first is the C++ glue. @@ -60,18 +57,18 @@ BUILT_SOURCES = \ ecc.py # This gets ecc.py installed in the right place -ourpython_PYTHON = \ - __init__.py \ +ourpython_PYTHON = \ + __init__.py \ ecc.py ourlib_LTLIBRARIES = _ecc.la # These are the source files that go into the shared library _ecc_la_SOURCES = \ - gr_syms_to_metrics.cc \ - gr_metrics_decode_viterbi_full_block.cc \ - gr_streams_encode_convolutional.cc \ - gr_streams_encode_turbo.cc \ + ecc_syms_to_metrics.cc \ + ecc_metrics_decode_viterbi_full_block.cc \ + ecc_streams_encode_convolutional.cc \ + ecc_streams_encode_turbo.cc \ ecc.cc # magic flags @@ -81,14 +78,15 @@ _ecc_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version _ecc_la_LIBADD = \ libecc/libecc.la \ $(PYTHON_LDFLAGS) \ + $(GNURADIO_CORE_LIBS) \ -lstdc++ # These headers get installed in ${prefix}/include/gnuradio grinclude_HEADERS = \ - gr_syms_to_metrics.h \ - gr_metrics_decode_viterbi_full_block.h \ - gr_streams_encode_convolutional.h \ - gr_streams_encode_turbo.h + ecc_syms_to_metrics.h \ + ecc_metrics_decode_viterbi_full_block.h \ + ecc_streams_encode_convolutional.h \ + ecc_streams_encode_turbo.h # These swig headers get installed in ${prefix}/include/gnuradio/swig swiginclude_HEADERS = $(LOCAL_IFILES) diff --git a/gr-error-correcting-codes/src/lib/ecc.i b/gr-error-correcting-codes/src/lib/ecc.i index 32ea9d2b2..3c6ea1e85 100644 --- a/gr-error-correcting-codes/src/lib/ecc.i +++ b/gr-error-correcting-codes/src/lib/ecc.i @@ -27,15 +27,15 @@ %{ #include "gnuradio_swig_bug_workaround.h" // mandatory bug fix -#include -#include -#include -#include +#include +#include +#include +#include #include %} -%include "gr_streams_encode_convolutional.i" -%include "gr_streams_encode_turbo.i" -%include "gr_metrics_decode_viterbi_full_block.i" -%include "gr_syms_to_metrics.i" +%include "ecc_streams_encode_convolutional.i" +%include "ecc_streams_encode_turbo.i" +%include "ecc_metrics_decode_viterbi_full_block.i" +%include "ecc_syms_to_metrics.i" diff --git a/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.cc b/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.cc new file mode 100644 index 000000000..dfb00932a --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.cc @@ -0,0 +1,245 @@ +/* -*- 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 +#include +#include +#include + +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 &code_generator, + bool do_termination, + int start_memory_state, + int end_memory_state) +{ + 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)); +} + +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 &code_generator, + const std::vector &code_feedback, + bool do_termination, + int start_memory_state, + int end_memory_state) +{ + return ecc_metrics_decode_viterbi_full_block_feedback_sptr + (new ecc_metrics_decode_viterbi_full_block + (sample_precision, + frame_size_bits, + n_code_inputs, + n_code_outputs, + code_generator, + code_feedback, + do_termination, + start_memory_state, + end_memory_state)); +} + +ecc_metrics_decode_viterbi_full_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 &code_generator, + bool do_termination, + int start_memory_state, + int end_memory_state) + : gr_block ("metrics_decode_viterbi_full_block", + gr_make_io_signature (0, 0, 0), + gr_make_io_signature (0, 0, 0)) +{ + d_encoder = new encoder_convolutional (frame_size_bits, + n_code_inputs, + n_code_outputs, + code_generator, + do_termination, + start_memory_state, + end_memory_state); + + setup_io_signatures (sample_precision, n_code_inputs, n_code_outputs); +} + +ecc_metrics_decode_viterbi_full_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 &code_generator, + const std::vector &code_feedback, + bool do_termination, + int start_memory_state, + int end_memory_state) + : gr_block ("metrics_decode_viterbi_full_block_feedback", + gr_make_io_signature (0, 0, 0), + gr_make_io_signature (0, 0, 0)) +{ + d_encoder = new encoder_convolutional (frame_size_bits, + n_code_inputs, + n_code_outputs, + code_generator, + code_feedback, + do_termination, + start_memory_state, + end_memory_state); + + setup_io_signatures (sample_precision, n_code_inputs, n_code_outputs); +} + +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 +(int sample_precision, + int n_code_inputs, + int n_code_outputs) +{ + // create the decoder + // + // the input model: individual input streams; two per metric type + // (0-bit, 1-bit), single metric per input item (float, char, short, + // long) + // + // the "ic1l" output model: + // individual output streams per decoded code input stream; + // each item is a 'char' type with 1 bit aligned on the LSB. + + d_decoder = new decoder_viterbi_full_block (sample_precision, + d_encoder); + 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, + sizeof (char))); + + // determine the input signature element size + size_t l_input_item_size_bytes; + + if (sample_precision == 0) { + // float + l_input_item_size_bytes = sizeof (float); + d_in_buf = new code_input_if (n_code_outputs); + } else if (sample_precision <= 8) { + // use char + l_input_item_size_bytes = sizeof (char); + d_in_buf = new code_input_ic (n_code_outputs); + } else if (sample_precision <= 16) { + // use short + l_input_item_size_bytes = sizeof (short); + d_in_buf = new code_input_is (n_code_outputs); + } else { + // use long + l_input_item_size_bytes = sizeof (long); + 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, + l_input_item_size_bytes)); +} + +void ecc_metrics_decode_viterbi_full_block::forecast +(int noutput_items, + gr_vector_int &ninput_items_required) +{ + int ninput_items = d_decoder->compute_n_input_items (noutput_items); + size_t ninputs = ninput_items_required.size(); + for (size_t n = 0; n < ninputs; n++) + ninput_items_required[n] = ninput_items; +} + +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) +{ + // 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 + 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 + + // setup the i/o buffers + + d_in_buf->set_buffer ((void**)(&input_items[0]), t_n_input_items); + d_out_buf->set_buffer ((void**)(&output_items[0]), noutput_items); + + // "work" is handled by the decoder; which returns the actual number + // of input items (metrics) used. + + t_n_input_items = d_decoder->decode (d_in_buf, d_out_buf, + (size_t) noutput_items); + + // consume the number of used input items on all input streams + + consume_each (t_n_input_items); + + // returns number of items written to each output stream + + return (noutput_items); +} diff --git a/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.h b/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.h new file mode 100644 index 000000000..9f37f0525 --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.h @@ -0,0 +1,165 @@ +/* -*- 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_ECC_METRICS_DECODE_VITERBI_FULL_BLOCK_H +#define INCLUDED_ECC_METRICS_DECODE_VITERBI_FULL_BLOCK_H + +#include +#include +#include + +class ecc_metrics_decode_viterbi_full_block; + +typedef boost::shared_ptr +ecc_metrics_decode_viterbi_full_block_sptr, +ecc_metrics_decode_viterbi_full_block_feedback_sptr; + +ecc_metrics_decode_viterbi_full_block_sptr +ecc_make_metrics_decode_viterbi_full_block +(int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + std::vector code_generator, + bool do_termination = true, + int start_memory_state = 0, + int end_memory_state = 0); + +ecc_metrics_decode_viterbi_full_block_feedback_sptr +ecc_make_metrics_decode_viterbi_full_block_feedback +(int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + std::vector code_generator, + std::vector code_feedback, + bool do_termination = true, + int start_memory_state = 0, + int end_memory_state = 0); + +/*! + * \brief Decode the incoming streams using a Viterbi-style decoder, + * full trellis block decoding. + * + * input: symbol metrics data. + * + * output: stream(s) of char, single bit stored in the LSB. + */ + +class ecc_metrics_decode_viterbi_full_block : public gr_block +{ +protected: + 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 &code_generator, + bool do_termination, + int start_memory_state, + int end_memory_state); + + 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 &code_generator, + const std::vector &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. + * + * 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 + */ + + ecc_metrics_decode_viterbi_full_block + (int sample_precision, + int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &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 &code_generator, + const std::vector &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; + +public: + ~ecc_metrics_decode_viterbi_full_block (); + + virtual void forecast (int noutput_items, + gr_vector_int &ninput_items_required); + + virtual int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_ECC_METRICS_DECODE_VITERBI_FULL_BLOCK_H */ diff --git a/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.i b/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.i new file mode 100644 index 000000000..85f6b6db3 --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_metrics_decode_viterbi_full_block.i @@ -0,0 +1,77 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +GR_SWIG_BLOCK_MAGIC(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_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 &code_generator, + bool do_termination, + int start_memory_state, + int end_memory_state); + +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 &code_generator, + const std::vector &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 &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 &code_generator, + const std::vector &code_feedback, + bool do_termination, + int start_memory_state, + int end_memory_state); +}; diff --git a/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.cc b/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.cc new file mode 100644 index 000000000..a0ffd1ab1 --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.cc @@ -0,0 +1,208 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +ecc_streams_encode_convolutional_sptr +ecc_make_streams_encode_convolutional +(int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + bool do_termination, + int start_memory_state, + int end_memory_state) +{ + return ecc_streams_encode_convolutional_sptr + (new ecc_streams_encode_convolutional (frame_size_bits, + n_code_inputs, + n_code_outputs, + code_generator, + do_termination, + start_memory_state, + end_memory_state)); +} + +ecc_streams_encode_convolutional_sptr +ecc_make_streams_encode_convolutional_feedback +(int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + const std::vector &code_feedback, + bool do_termination, + int start_memory_state, + int end_memory_state) +{ + return ecc_streams_encode_convolutional_sptr + (new ecc_streams_encode_convolutional (frame_size_bits, + n_code_inputs, + n_code_outputs, + code_generator, + code_feedback, + do_termination, + start_memory_state, + end_memory_state)); +} + +ecc_streams_encode_convolutional::ecc_streams_encode_convolutional +(int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generators, + bool 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. + + d_encoder = new encoder_convolutional (frame_size_bits, + n_code_inputs, + n_code_outputs, + code_generators, + do_termination, + start_memory_state, + end_memory_state); + + setup_io_signatures (n_code_inputs, n_code_outputs); +} + +ecc_streams_encode_convolutional::ecc_streams_encode_convolutional +(int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generators, + const std::vector &code_feedback, + bool 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. + + d_encoder = new encoder_convolutional (frame_size_bits, + n_code_inputs, + n_code_outputs, + code_generators, + code_feedback, + do_termination, + start_memory_state, + end_memory_state); + + setup_io_signatures (n_code_inputs, n_code_outputs); +} + +void +ecc_streams_encode_convolutional::setup_io_signatures +(int n_code_inputs, + int n_code_outputs) +{ + // create the correct input signature; 1 bit per input char + + d_in_buf = new code_input_ic1l (n_code_inputs); + set_input_signature (gr_make_io_signature (n_code_inputs, + n_code_inputs, + sizeof (char))); + + // create the correct output signature; 1 bit per output char + + d_out_buf = new code_output_ic1l (n_code_outputs); + set_output_signature (gr_make_io_signature (n_code_outputs, + n_code_outputs, + sizeof (char))); +} + +ecc_streams_encode_convolutional::~ecc_streams_encode_convolutional +() +{ + delete d_encoder; + d_encoder = 0; + delete d_in_buf; + d_in_buf = 0; + delete d_out_buf; + d_out_buf = 0; +} + +/* + * Compute the number of input items needed to produce 'n_output' + * bits. Handled internally by the encoder. + */ + +void ecc_streams_encode_convolutional::forecast +(int noutput_items, + gr_vector_int &ninput_items_required) +{ + int ninput_items = d_encoder->compute_n_input_bits (noutput_items); + size_t ninputs = ninput_items_required.size(); + for (size_t n = 0; n < ninputs; n++) + ninput_items_required[n] = ninput_items; +} + +int +ecc_streams_encode_convolutional::general_work +(int noutput_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_encoder->compute_n_input_bits (noutput_items); +#if 1 + 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 + // setup the i/o buffers + + d_in_buf->set_buffer ((void**)(&input_items[0]), t_n_input_items); + d_out_buf->set_buffer ((void**)(&output_items[0]), noutput_items); + + // "work" is handled by the encoder; which returns the actual number + // of input items (1-bit char's) used. + + 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); + + // returns number of items written to each output stream + + return (noutput_items); +} diff --git a/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.h b/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.h new file mode 100644 index 000000000..19f7ea8c1 --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.h @@ -0,0 +1,158 @@ +/* -*- 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_ECC_STREAMS_ENCODE_CONVOLUTIONAL_H +#define INCLUDED_ECC_STREAMS_ENCODE_CONVOLUTIONAL_H + +#include +#include + +/*! + * \brief Encode the incoming streams using a convolutional encoder + * + * input: streams of char, one stream per input as defined by the + * instantiated code, using only the right-most justified bit as + * the single input bit per input item. + * + * output: streams of char, one stream per output as defined by the + * instantiated code, using only the right-most justified bit as + * the single output bit per output item. + * + * frame_size_bits: if == 0, then do streaming encoding ("infinite" + * trellis); otherwise this is the frame size in bits to encode + * before terminating the trellis. This value -does not- include + * any termination bits. + * + * n_code_inputs: + * n_code_outputs: + * code_generator: vector of integers (32 bit) representing the code + * to be implemented. E.g. "4" in binary is "100", which would be + * "D^2" for code generation. "6" == 110b == "D^2 + D" + * ==> The vector is listed in order for each output stream, so if there + * are 2 input streams (I1, I2) [specified in "n_code_inputs"] + * and 2 output streams (O1, O2) [specified in "n_code_outputs"], + * then the vector would be the code generator for: + * [I1->O1, I2->O1, I1->O2, I2->O2] + * with each element being an integer representation of the code. + * + * do_termination: valid only if frame_size_bits != 0, and defines + * whether or not to use trellis termination. Default is to use + * termination when doing block coding. + * + * start_memory_state: when starting a new block, the starting memory + * state to begin encoding; there will be a helper function to + * assist in creating this value for a given set of inputs; + * default is the "all zero" state. + * + * end_memory_state: when terminating a block, the ending memory + * state to stop encoding; there will be a helper function to + * assist in creating this value for a given set of inputs; + * default is the "all zero" state. + */ + +class ecc_streams_encode_convolutional; +typedef boost::shared_ptr + ecc_streams_encode_convolutional_sptr; + +ecc_streams_encode_convolutional_sptr +ecc_make_streams_encode_convolutional +(int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + bool do_termination = true, + int start_memory_state = 0, + int end_memory_state = 0); + +ecc_streams_encode_convolutional_sptr +ecc_make_streams_encode_convolutional_feedback +(int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + const std::vector &code_feedback, + bool do_termination = true, + int start_memory_state = 0, + int end_memory_state = 0); + +class ecc_streams_encode_convolutional : public gr_block +{ +protected: + friend ecc_streams_encode_convolutional_sptr + ecc_make_streams_encode_convolutional + (int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + bool do_termination, + int start_memory_state, + int end_memory_state); + + friend ecc_streams_encode_convolutional_sptr + ecc_make_streams_encode_convolutional_feedback + (int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + const std::vector &code_feedback, + bool do_termination, + int start_memory_state, + int end_memory_state); + + ecc_streams_encode_convolutional (int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + bool do_termination, + int start_memory_state, + int end_memory_state); + + ecc_streams_encode_convolutional (int frame_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + const std::vector &code_feedback, + bool do_termination, + int start_memory_state, + int end_memory_state); + + void setup_io_signatures (int n_code_inputs, int n_code_outputs); + + encoder_convolutional* d_encoder; + code_input_ptr d_in_buf; + code_output_ptr d_out_buf; + +public: + ~ecc_streams_encode_convolutional (); + + inline encoder_convolutional* encoder () {return (d_encoder);}; + + virtual void forecast (int noutput_items, + gr_vector_int &ninput_items_required); + + virtual int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_ECC_STREAMS_ENCODE_CONVOLUTIONAL_H */ diff --git a/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.i b/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.i new file mode 100644 index 000000000..7563a95db --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_streams_encode_convolutional.i @@ -0,0 +1,77 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +GR_SWIG_BLOCK_MAGIC(ecc,streams_encode_convolutional); + +// Rename second constructor +%rename(streams_encode_convolutional_feedback) ecc_make_streams_encode_convolutional_feedback; + +// support vectors of these ... for use in the convolutional decoder +// as well as Turbo Codes (both encoder and decoder). + +namespace std { + %template(x_vector_ecc_streams_encode_convolutional_sptr) vector; +}; + +ecc_streams_encode_convolutional_sptr +ecc_make_streams_encode_convolutional +(int block_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + bool do_termination = true, + int start_memory_state = 0, + int end_memory_state = 0); + +ecc_streams_encode_convolutional_sptr +ecc_make_streams_encode_convolutional_feedback +(int block_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + const std::vector &code_feedback, + bool do_termination = true, + int start_memory_state = 0, + int end_memory_state = 0); + +class ecc_streams_encode_convolutional : public gr_block +{ +private: + ecc_streams_encode_convolutional + (int block_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + bool do_termination, + int start_memory_state, + int end_memory_state); + + ecc_streams_encode_convolutional + (int block_size_bits, + int n_code_inputs, + int n_code_outputs, + const std::vector &code_generator, + const std::vector &code_feedback, + bool do_termination, + int start_memory_state, + int end_memory_state); +}; diff --git a/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.cc b/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.cc new file mode 100644 index 000000000..0c4cfd1a4 --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.cc @@ -0,0 +1,197 @@ +/* -*- 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 +#include +#include +#include + +ecc_streams_encode_turbo_sptr +ecc_make_streams_encode_turbo +(int n_code_inputs, + int n_code_outputs, + const std::vector &encoders, + const std::vector &interleavers) +{ + return ecc_streams_encode_turbo_sptr + (new ecc_streams_encode_turbo (n_code_inputs, + n_code_outputs, + encoders, + interleavers)); +} + +ecc_streams_encode_turbo::ecc_streams_encode_turbo +(int n_code_inputs, + int n_code_outputs, + const std::vector &encoders, + const std::vector &interleavers) + : gr_block ("streams_encode_turbo", + 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. But ... check out individual encoders, to make + // sure the total I/O matches those specified by the user. + + d_n_encoders = encoders.size (); + + if (d_n_encoders < 2) { + std::cerr << "ecc_streams_encode_turbo: Error: " + "too few (" << d_n_encoders << ") encoders specified; a Turbo " + "code requires at least 2 constituent encoders.\n"; + assert (0); + } + + // make sure that the block size and termination are consistent for + // all encoders; warn the user if not, since it doesn't really + // matter to the encoder (but it might to the decoder; remains to be + // seen). + + encoder_convolutional* t_ec = encoders[0]->encoder (); + d_block_size_bits = t_ec->block_size_bits (); + d_do_termination = t_ec->do_termination (); + bool t_diff_block_size, t_diff_termination; + t_diff_block_size = t_diff_termination = false; + + for (size_t m = 1; m < d_n_encoders; m++) { + t_ec = encoders[0]->encoder (); + size_t t_block_size_bits = t_ec->block_size_bits (); + if (t_block_size_bits != d_block_size_bits) + t_diff_block_size = true; + bool t_do_termination = t_ec->do_termination (); + if (t_do_termination != d_do_termination) + t_do_termination = true; + } + + if (t_diff_block_size == true) { + std::cout << "ecc_streams_encode_turbo: Warning: " + "Some constituent encoders have different block size (bits).\n"; + } + if (t_diff_termination == true) { + std::cout << "ecc_streams_encode_turbo: Warning: " + "Some constituent encoders are differently terminationed.\n"; + } + + std::cout << "ecc_streams_encode_turbo: setup:\n" + "d_n_encoders = " << d_n_encoders << "\n" + "n_code_inputs = " << n_code_inputs << "\n" + "n_code_outputs = " << n_code_outputs << "\n\n" + "Individual Encoders:\n"; + + for (size_t m = 0; m < d_n_encoders; m++) { + t_ec = encoders[m]->encoder (); + std::cout << " [" << (m+1) << "]:\n" + "n_code_inputs = " << (t_ec->n_code_inputs()) << "\n" + "n_code_outputs = " << (t_ec->n_code_outputs()) << "\n" + "block_size_bits = " << (t_ec->block_size_bits()) << "\n" + "do_termination = " << + ((t_ec->do_termination()==true)?"true":"false") << "\n"; + } + +#if 1 + assert (0); +#else + if (d_n_encoders != (interleavers.size())) {} + + d_encoder = new encoder_turbo (n_code_inputs, + n_code_outputs, + code_generators, + do_termination, + start_memory_state, + end_memory_state); +#endif + + // create the correct input signature; 1 bit per input char + + d_in_buf = new code_input_ic1l (n_code_inputs); + set_input_signature (gr_make_io_signature (n_code_inputs, + n_code_inputs, + sizeof (char))); + + // create the correct output signature; 1 bit per output char + + d_out_buf = new code_output_ic1l (n_code_outputs); + set_output_signature (gr_make_io_signature (n_code_outputs, + n_code_outputs, + sizeof (char))); +} + +ecc_streams_encode_turbo::~ecc_streams_encode_turbo +() +{ + delete d_encoder; + d_encoder = 0; + delete d_in_buf; + d_in_buf = 0; + delete d_out_buf; + d_out_buf = 0; +} + +void ecc_streams_encode_turbo::forecast +(int noutput_items, + gr_vector_int &ninput_items_required) +{ + int ninput_items = d_encoder->compute_n_input_bits (noutput_items); + size_t ninputs = ninput_items_required.size(); + for (size_t n = 0; n < ninputs; n++) + ninput_items_required[n] = ninput_items; +} + +int +ecc_streams_encode_turbo::general_work +(int noutput_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_encoder->compute_n_input_bits (noutput_items); +#if 1 + 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 + // setup the i/o buffers + + d_in_buf->set_buffer ((void**)(&input_items[0]), t_n_input_items); + d_out_buf->set_buffer ((void**)(&output_items[0]), noutput_items); + + // "work" is handled by the encoder; which returns the actual number + // of input items (1-bit char's) used. + + 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); + + // returns number of items written to each output stream + + return (noutput_items); +} diff --git a/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.h b/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.h new file mode 100644 index 000000000..16f4427c5 --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.h @@ -0,0 +1,107 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef INCLUDED_ECC_STREAMS_ENCODE_TURBO_H +#define INCLUDED_ECC_STREAMS_ENCODE_TURBO_H + +#include +#include + +#if 0 +#include +#else +#include +#endif + +/*! + * \brief Encode the incoming stream(s) using a turbo encoder + * + * input: streams of char, one stream per input as defined by the + * instantiated code, using only the right-most justified bit as + * the single input bit per input item. + * + * output: streams of char, one stream per output as defined by the + * instantiated code, using only the right-most justified bit as + * the single output bit per output item. + * + * n_code_inputs: + * n_code_outputs: the total number of code inputs and outputs for the + * overall turbo encoder (not just the constituent codes). + * + * encoders: the constituent encoders to be used; all -should- be + * configured with the same "block_size" and "termination", though + * from this encoder's perspective it doesn't really matter. + * + * interleavers: the interleavers to use before each encoder, + * respectively, except the first encoder which will not use an + * interleaver. + */ + +class ecc_streams_encode_turbo; + +typedef boost::shared_ptr +ecc_streams_encode_turbo_sptr; + +ecc_streams_encode_turbo_sptr +ecc_make_streams_encode_turbo +(int n_code_inputs, + int n_code_outputs, + const std::vector &encoders, + const std::vector &interleavers); + +class ecc_streams_encode_turbo : public gr_block +{ +protected: + friend ecc_streams_encode_turbo_sptr + ecc_make_streams_encode_turbo + (int n_code_inputs, + int n_code_outputs, + const std::vector &d_encoders, + const std::vector &d_interleavers); + + ecc_streams_encode_turbo + (int n_code_inputs, + int n_code_outputs, + const std::vector &d_encoders, + const std::vector &d_interleavers); + + std::vector d_encoders; + std::vector d_interleavers; + size_t d_n_encoders, d_block_size_bits; + bool d_do_termination; + encoder_turbo* d_encoder; + code_input_ptr d_in_buf; + code_output_ptr d_out_buf; + +public: + ~ecc_streams_encode_turbo (); + + virtual void forecast (int noutput_items, + gr_vector_int &ninput_items_required); + + virtual int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_ECC_STREAMS_ENCODE_TURBO_H */ diff --git a/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.i b/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.i new file mode 100644 index 000000000..e453cdab9 --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_streams_encode_turbo.i @@ -0,0 +1,41 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +GR_SWIG_BLOCK_MAGIC(ecc,streams_encode_turbo); + +#include + +ecc_streams_encode_turbo_sptr +ecc_make_streams_encode_turbo +(int n_code_inputs, + int n_code_outputs, + const std::vector &encoders, + const std::vector &interleavers); + +class ecc_streams_encode_turbo : public gr_block +{ + ecc_streams_encode_turbo + (int frame_size_bits, + int n_code_inputs, + const std::vector &encoders, + const std::vector &interleavers); +}; diff --git a/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc b/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc new file mode 100644 index 000000000..c60eec8a7 --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.cc @@ -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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +ecc_syms_to_metrics_sptr +ecc_make_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit, + gr_feval_ff* pdf_fcn_1_bit, + int n_samples, + float min_sample, + float max_sample, + int sample_precision) +{ + return ecc_syms_to_metrics_sptr + (new ecc_syms_to_metrics (pdf_fcn_0_bit, + pdf_fcn_1_bit, + n_samples, + min_sample, + max_sample, + sample_precision)); +} + +/* + * dummy functions and variables to get the float(*)(float) function + * to work properly with the gr_feval_XX stuff. + */ + +static gr_feval_ff* l_pdf_fcn_0_bit; +static gr_feval_ff* l_pdf_fcn_1_bit; + +static float pdf_fcn_0 (float x) +{ + return (l_pdf_fcn_0_bit->eval (x)); +} + +static float pdf_fcn_1 (float x) +{ + return (l_pdf_fcn_1_bit->eval (x)); +} + +ecc_syms_to_metrics::ecc_syms_to_metrics +(gr_feval_ff* pdf_fcn_0_bit, + gr_feval_ff* pdf_fcn_1_bit, + int n_samples, + float min_sample, + float max_sample, + int sample_precision) + : gr_block ("syms_to_metrics", + gr_make_io_signature (1, -1, sizeof (float)), + gr_make_io_signature (0, 0, 0)) +{ + // 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. + + 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. + + d_code_metrics_table = libecc_code_metrics_create_table + (&pdf_fcn_0, + &pdf_fcn_1, + n_samples, + min_sample, + max_sample, + sample_precision); + + // get the output item size in bytes from the new code_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_output_signature (gr_make_io_signature (1, -1, d_out_item_size_bytes)); +} + +bool ecc_syms_to_metrics::check_topology (int ninputs, int noutputs) +{ + // there are 2 output streams per input stream; the first is ~to + // log(p(0|x)) = log-probability of a 0-bit given the input symbol + // 'x'; the second is ~to log(p(1|x)). + + return ((noutputs == (2*ninputs)) ? true : false); +} + +void +ecc_syms_to_metrics::forecast +(int noutput_items, + gr_vector_int &ninput_items_required) +{ + // always 1:1, for all streams + for (size_t n = 0; n < ninput_items_required.size(); n++) { + ninput_items_required[n] = noutput_items; + } +} + +int +ecc_syms_to_metrics::general_work +(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) +{ + size_t l_n_output_items = noutput_items; + + for (size_t n = 0; n < input_items.size(); n++) { + float* t_in_buf = (float*)(&input_items[n]); + void* t_out_buf_0_bit = (void*)(&(output_items[2*n])); + void* t_out_buf_1_bit = (void*)(&(output_items[(2*n)+1])); + + d_code_metrics_table->convert (l_n_output_items, t_in_buf, + t_out_buf_0_bit, t_out_buf_1_bit); + } + + // consume the number of used input items on all input streams + + consume_each (noutput_items); + + // returns number of items written to each output stream + + return (noutput_items); +} diff --git a/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.h b/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.h new file mode 100644 index 000000000..0f4577ad7 --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.h @@ -0,0 +1,124 @@ +/* -*- 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_SYMS_TO_METRICS_H +#define INCLUDED_SYMS_TO_METRICS_H + +#include +#include +#include +#include + +class ecc_syms_to_metrics; +typedef boost::shared_ptr ecc_syms_to_metrics_sptr; + +ecc_syms_to_metrics_sptr ecc_make_syms_to_metrics +(gr_feval_ff* pdf_fcn_0_bit, + gr_feval_ff* pdf_fcn_1_bit, + int n_samples, + float min_sample, + float max_sample, + int sample_precision); + +/*! + * \brief Convert the input stream(s) of soft (float) symbols to + * log-probability metrics of user-specified precision; output is 2 + * streams per input stream, each stream consisting of the metric for + * receiving a 0-bit and 1-bit, respectively, with the lower-numbered + * stream being the 0-bit. + * + * input: stream(s) of float; output: stream(s) of metrics + */ + +class ecc_syms_to_metrics : public gr_block +{ +protected: + friend ecc_syms_to_metrics_sptr + ecc_make_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit, + gr_feval_ff* pdf_fcn_1_bit, + int n_samples, + float min_sample, + float max_sample, + int sample_precision); + +/* + * ecc_syms_to_metrics: Convert the input soft (float) symbols into + * log-probabilities (metrics) for use in the convolutional + * decoder. Samples the provided PDF function in 'n_samples' + * places from 'min_sample' to 'max_sample', takes the log of that + * value, then converts the result into a given precision and + * stores all results in a "handy dandy" lookup table for much + * faster processing. + * + * pdf_fcn_0_bit: point to a probability distribution function which + * takes a float and returns a float, for the 0-bit probabilities. + * + * pdf_fcn_1_bit: point to a probability distribution function which + * takes a float and returns a float, for the 1-bit probabilities. + * + * n_samples: the number of samples between min_sample and max_sample + * to store in the lookup table. Must be at least 2, but + * otherwise is limited only by the amount of available memory; + * generally, 65536 (1 << 16) is plenty of samples. + * + * min_sample: the minimum value below which any incoming value is + * "rounded" up. + * + * max_sample: the maximum value above which any incoming value is + * "rounded" down. + * + * sample_precision: the precision with which to sample the returned + * value of the PDF function. + * + Cannot be < 0 or > 32. + * + "soft float" == 0 + * + otherwise, convert to an integer of the given value + * + * in "work", finds the (linearly) closest sample value for the given + * input and outputs the metric for a 0-bit input on the first + * stream and a 1-bit input on the second stream. + * + */ + + ecc_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit, + gr_feval_ff* pdf_fcn_1_bit, + int n_samples, + float min_sample, + float max_sample, + int sample_precision); + + size_t d_out_item_size_bytes; + code_metrics_table* d_code_metrics_table; + +public: + ~ecc_syms_to_metrics() {delete d_code_metrics_table;}; + + bool check_topology (int ninputs, int noutputs); + + void forecast (int noutput_items, gr_vector_int &ninput_items_required); + + int general_work (int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); +}; + +#endif /* INCLUDED_SYMS_TO_METRICS_H */ diff --git a/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.i b/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.i new file mode 100644 index 000000000..a51a15b9b --- /dev/null +++ b/gr-error-correcting-codes/src/lib/ecc_syms_to_metrics.i @@ -0,0 +1,41 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +GR_SWIG_BLOCK_MAGIC(ecc,syms_to_metrics); + +ecc_syms_to_metrics_sptr ecc_make_syms_to_metrics +(gr_feval_ff* pdf_fcn_0_bit, + gr_feval_ff* pdf_fcn_1_bit, + int n_samples, + float min_sample, + float max_sample, + int sample_precision); + +class ecc_syms_to_metrics : public gr_block +{ + ecc_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit, + gr_feval_ff* pdf_fcn_1_bit, + int n_samples, + float min_sample, + float max_sample, + int sample_precision); +}; diff --git a/gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.cc b/gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.cc deleted file mode 100644 index 94a7fe44a..000000000 --- a/gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.cc +++ /dev/null @@ -1,228 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -gr_metrics_decode_viterbi_full_block_sptr -gr_make_metrics_decode_viterbi_full_block -(int sample_precision, - int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination, - int start_memory_state, - int end_memory_state) -{ - return gr_metrics_decode_viterbi_full_block_sptr - (new gr_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)); -} - -gr_metrics_decode_viterbi_full_block_feedback_sptr -gr_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 &code_generator, - const std::vector &code_feedback, - bool do_termination, - int start_memory_state, - int end_memory_state) -{ - return gr_metrics_decode_viterbi_full_block_feedback_sptr - (new gr_metrics_decode_viterbi_full_block - (sample_precision, - frame_size_bits, - n_code_inputs, - n_code_outputs, - code_generator, - code_feedback, - do_termination, - start_memory_state, - end_memory_state)); -} - -gr_metrics_decode_viterbi_full_block::gr_metrics_decode_viterbi_full_block -(int sample_precision, - int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination, - int start_memory_state, - int end_memory_state) - : gr_block ("metrics_decode_viterbi_full_block", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (0, 0, 0)) -{ - d_encoder = new encoder_convolutional_ic1_ic1 (frame_size_bits, - n_code_inputs, - n_code_outputs, - code_generator, - do_termination, - start_memory_state, - end_memory_state); - - setup_io_signatures (sample_precision, n_code_inputs, n_code_outputs); -} - -gr_metrics_decode_viterbi_full_block::gr_metrics_decode_viterbi_full_block -(int sample_precision, - int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - const std::vector &code_feedback, - bool do_termination, - int start_memory_state, - int end_memory_state) - : gr_block ("metrics_decode_viterbi_full_block_feedback", - gr_make_io_signature (0, 0, 0), - gr_make_io_signature (0, 0, 0)) -{ - d_encoder = new encoder_convolutional_ic1_ic1 (frame_size_bits, - n_code_inputs, - n_code_outputs, - code_generator, - code_feedback, - do_termination, - start_memory_state, - end_memory_state); - - setup_io_signatures (sample_precision, n_code_inputs, n_code_outputs); -} - -gr_metrics_decode_viterbi_full_block::~gr_metrics_decode_viterbi_full_block -() -{ - delete d_decoder; - delete d_encoder; -} - -void -gr_metrics_decode_viterbi_full_block::setup_io_signatures -(int sample_precision, - int n_code_inputs, - int n_code_outputs) -{ - // create the decoder using: - // - // the "i1" input model: individual input streams; two per metric - // type (0-bit, 1-bit), single metric per input item (char, short, long) - // - // the "ic1" output model: - // individual output streams per decoded code input stream; - // each item is a 'char' type with 1 bit aligned on the LSB. - - d_decoder = new decoder_viterbi_full_block_i1_ic1 (sample_precision, - d_encoder); - - // 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, - sizeof (char))); - - // determine the input signature element size - size_t l_input_item_size_bytes; - - if (sample_precision == 0) { - // float - l_input_item_size_bytes = sizeof (float); - } else if (sample_precision <= 8) { - // use char - l_input_item_size_bytes = sizeof (char); - } else if (sample_precision <= 16) { - // use short - l_input_item_size_bytes = sizeof (short); - } else { - // use long - l_input_item_size_bytes = sizeof (long); - } - - set_input_signature (gr_make_io_signature (2*d_n_code_outputs, - 2*d_n_code_outputs, - l_input_item_size_bytes)); -} - -void gr_metrics_decode_viterbi_full_block::forecast -(int noutput_items, - gr_vector_int &ninput_items_required) -{ - int ninput_items = d_decoder->compute_n_input_metrics (noutput_items); - size_t ninputs = ninput_items_required.size(); - for (size_t n = 0; n < ninputs; n++) - ninput_items_required[n] = ninput_items; -} - -int -gr_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) -{ - // FIXME: compute the actual number of output items (1 bit char's) created. - - size_t t_n_input_items = d_decoder->compute_n_input_metrics (noutput_items); - 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)); - - // "work" is handled by the decoder; which returns the actual number - // of input items (metrics) used. - - t_n_input_items = d_decoder->decode ((const char**)(&input_items[0]), - (char**)(&output_items[0]), - noutput_items); - - // consume the number of used input items on all input streams - - consume_each (t_n_input_items); - - // returns number of items written to each output stream - - return (noutput_items); -} diff --git a/gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.h b/gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.h deleted file mode 100644 index 57ca1bab1..000000000 --- a/gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.h +++ /dev/null @@ -1,163 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef INCLUDED_GR_METRICS_DECODE_VITERBI_FULL_BLOCK_H -#define INCLUDED_GR_METRICS_DECODE_VITERBI_FULL_BLOCK_H - -#include -#include -#include - -class gr_metrics_decode_viterbi_full_block; - -typedef boost::shared_ptr -gr_metrics_decode_viterbi_full_block_sptr, -gr_metrics_decode_viterbi_full_block_feedback_sptr; - -gr_metrics_decode_viterbi_full_block_sptr -gr_make_metrics_decode_viterbi_full_block -(int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - std::vector code_generator, - bool do_termination = true, - int start_memory_state = 0, - int end_memory_state = 0); - -gr_metrics_decode_viterbi_full_block_feedback_sptr -gr_make_metrics_decode_viterbi_full_block_feedback -(int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - std::vector code_generator, - std::vector code_feedback, - bool do_termination = true, - int start_memory_state = 0, - int end_memory_state = 0); - -/*! - * \brief Decode the incoming streams using a Viterbi-style decoder, - * full trellis block decoding. - * - * input: symbol metrics data. - * - * output: stream(s) of char, single bit stored in the LSB. - */ - -class gr_metrics_decode_viterbi_full_block : public gr_block -{ - friend gr_metrics_decode_viterbi_full_block_sptr - gr_make_metrics_decode_viterbi_full_block - (int sample_precision, - int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination, - int start_memory_state, - int end_memory_state); - - friend gr_metrics_decode_viterbi_full_block_feedback_sptr - gr_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 &code_generator, - const std::vector &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. - * - * code_generator: vector of integers (32 bit) representing the code - * to be implemented in octal form. E.g. "04" in binary is "100", - * which would be "D^2" for code generation. "06" == 110b == "D^2 + D" - * ==> The vector is listed in order for each input stream, so if there - * are 2 input streams (I1, I2) [specified in "n_code_inputs"] - * and 2 output streams (O1, O2) [specified in "n_code_outputs"], - * then the vector would be the code generator for: - * [I1->O1, I1->O2, I2->O1, I2->O2] - * with each element being the octal representation of the code. - * - * do_termination is valid only if frame_size_bits != 0, and defines - * whether or not to to trellis termination. - * - * do_mux_input: is true, then the one input stream will be - * interpreted as the multiplexing all of the input bits. For - * example for a 3 input decoder, the input stream would be - * [I1[k], I2[k], I3[k], I1[k+1], I2[k+1], ...], where "k" is the - * input sample time, and "I1" through "I3" are the 3 input - * streams. - * - * n_code_inputs: the number of decoder-input (encoder-output) - * streams, no matter if separate or mux'ed - * - * n_code_outputs: the number of decoder-output (encoder-input) streams - */ - - gr_metrics_decode_viterbi_full_block - (int sample_precision, - int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination, - int start_memory_state, - int end_memory_state); - - gr_metrics_decode_viterbi_full_block - (int sample_precision, - int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - const std::vector &code_feedback, - bool do_termination, - int start_memory_state, - int end_memory_state); - -public: - ~gr_metrics_decode_viterbi_full_block (); - - virtual void forecast (int noutput_items, - gr_vector_int &ninput_items_required); - - virtual int general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - -protected: - 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_i1_ic1* d_decoder; - encoder_convolutional_ic1_ic1* d_encoder; -}; - -#endif /* INCLUDED_GR_METRICS_DECODE_VITERBI_FULL_BLOCK_H */ diff --git a/gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.i b/gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.i deleted file mode 100644 index a7cd1ba25..000000000 --- a/gr-error-correcting-codes/src/lib/gr_metrics_decode_viterbi_full_block.i +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -GR_SWIG_BLOCK_MAGIC(gr,metrics_decode_viterbi_full_block); - -// corrected "class NAME" statement, which uses slightly different NAMEs - -typedef boost::shared_ptr -gr_metrics_decode_viterbi_full_block_feedback_sptr; - -LOCAL_GR_SWIG_BLOCK_MAGIC(gr,metrics_decode_viterbi_full_block_feedback); - -gr_metrics_decode_viterbi_full_block_sptr -gr_make_metrics_decode_viterbi_full_block -(int sample_precision, - int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination, - int start_memory_state, - int end_memory_state); - -gr_metrics_decode_viterbi_full_block_feedback_sptr -gr_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 &code_generator, - const std::vector &code_feedback, - bool do_termination, - int start_memory_state, - int end_memory_state); - -class gr_metrics_decode_viterbi_full_block : public gr_block -{ - gr_metrics_decode_viterbi_full_block - (int sample_precision, - int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination, - int start_memory_state, - int end_memory_state); - - gr_metrics_decode_viterbi_full_block - (int sample_precision, - int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - const std::vector &code_feedback, - bool do_termination, - int start_memory_state, - int end_memory_state); -}; diff --git a/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.cc b/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.cc deleted file mode 100644 index 98e292651..000000000 --- a/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.cc +++ /dev/null @@ -1,220 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -gr_streams_encode_convolutional_sptr -gr_make_streams_encode_convolutional -(int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination, - int start_memory_state, - int end_memory_state) -{ - return gr_streams_encode_convolutional_sptr - (new gr_streams_encode_convolutional (frame_size_bits, - n_code_inputs, - n_code_outputs, - code_generator, - do_termination, - start_memory_state, - end_memory_state)); -} - -gr_streams_encode_convolutional_sptr -gr_make_streams_encode_convolutional_feedback -(int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - const std::vector &code_feedback, - bool do_termination, - int start_memory_state, - int end_memory_state) -{ - return gr_streams_encode_convolutional_sptr - (new gr_streams_encode_convolutional (frame_size_bits, - n_code_inputs, - n_code_outputs, - code_generator, - code_feedback, - do_termination, - start_memory_state, - end_memory_state)); -} - -gr_streams_encode_convolutional::gr_streams_encode_convolutional -(int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generators, - bool 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. - - d_encoder = new encoder_convolutional_ic1_ic1 (frame_size_bits, - n_code_inputs, - n_code_outputs, - code_generators, - do_termination, - start_memory_state, - end_memory_state); - - setup_io_signatures (n_code_inputs, n_code_outputs); -} - -gr_streams_encode_convolutional::gr_streams_encode_convolutional -(int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generators, - const std::vector &code_feedback, - bool 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. - - d_encoder = new encoder_convolutional_ic1_ic1 (frame_size_bits, - n_code_inputs, - n_code_outputs, - code_generators, - code_feedback, - do_termination, - start_memory_state, - end_memory_state); - - setup_io_signatures (n_code_inputs, n_code_outputs); -} - -void -gr_streams_encode_convolutional::setup_io_signatures -(int n_code_inputs, - int n_code_outputs) -{ - fprintf (stderr, "gr_s_e_c: d_encoder == %X\n", (unsigned int)d_encoder); - - // create the correct input signature; 1 bit per input char - - set_input_signature (gr_make_io_signature (n_code_inputs, - n_code_inputs, - sizeof (char))); - - // create the correct output signature; 1 bit per output char - - set_output_signature (gr_make_io_signature (n_code_outputs, - n_code_outputs, - sizeof (char))); - - // no need to set the output multiple (to 1 item), since 1 is the - // default, and the encoder class handles the rest internally - - // no need to set the relative rate (# out / # in) because for each - // input bit per input stream there is 1 output bit per output - // stream ... with a little added for termination, but ignore those. -} - -gr_streams_encode_convolutional::~gr_streams_encode_convolutional -() -{ - delete d_encoder; - d_encoder = 0; -} - -/* - * Compute the number of input items needed to produce 'n_output' - * bits. Handled internally by the encoder. - */ - -void gr_streams_encode_convolutional::forecast -(int noutput_items, - gr_vector_int &ninput_items_required) -{ - fprintf (stderr, "gr_s_e_c::forecast: #out = %d\n", - noutput_items); - - int ninput_items = d_encoder->compute_n_input_bits (noutput_items); - - fprintf (stderr, "s_e_c::forecast: #out = %d, #in = %d\n", - noutput_items, ninput_items); - - size_t ninputs = ninput_items_required.size(); - for (size_t n = 0; n < ninputs; n++) - ninput_items_required[n] = ninput_items; -} - -int -gr_streams_encode_convolutional::general_work -(int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - fprintf (stderr, "gr_s_e_c::general_work: Starting #out = %d\n", - noutput_items); - - // FIXME: 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 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 - - // "work" is handled by the encoder; which returns the actual number - // of input items (1-bit char's) used. - - t_n_input_items = d_encoder->encode ((const char **)(&input_items[0]), - (char **)(&output_items[0]), - (size_t) noutput_items); - - assert (0); - - // consume the number of used input items on all input streams - - consume_each (t_n_input_items); - - // returns number of items written to each output stream - - return (noutput_items); -} diff --git a/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.h b/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.h deleted file mode 100644 index 66e910916..000000000 --- a/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.h +++ /dev/null @@ -1,155 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef INCLUDED_GR_STREAMS_ENCODE_CONVOLUTIONAL_H -#define INCLUDED_GR_STREAMS_ENCODE_CONVOLUTIONAL_H - -#include -#include - -/*! - * \brief Encode the incoming streams using a convolutional encoder - * - * input: streams of char, one stream per input as defined by the - * instantiated code, using only the right-most justified bit as - * the single input bit per input item. - * - * output: streams of char, one stream per output as defined by the - * instantiated code, using only the right-most justified bit as - * the single output bit per output item. - * - * frame_size_bits: if == 0, then do streaming encoding ("infinite" - * trellis); otherwise this is the frame size in bits to encode - * before terminating the trellis. This value -does not- include - * any termination bits. - * - * n_code_inputs: - * n_code_outputs: - * code_generator: vector of integers (32 bit) representing the code - * to be implemented. E.g. "4" in binary is "100", which would be - * "D^2" for code generation. "6" == 110b == "D^2 + D" - * ==> The vector is listed in order for each output stream, so if there - * are 2 input streams (I1, I2) [specified in "n_code_inputs"] - * and 2 output streams (O1, O2) [specified in "n_code_outputs"], - * then the vector would be the code generator for: - * [I1->O1, I2->O1, I1->O2, I2->O2] - * with each element being an integer representation of the code. - * - * do_termination: valid only if frame_size_bits != 0, and defines - * whether or not to use trellis termination. Default is to use - * termination when doing block coding. - * - * start_memory_state: when starting a new block, the starting memory - * state to begin encoding; there will be a helper function to - * assist in creating this value for a given set of inputs; - * default is the "all zero" state. - * - * end_memory_state: when terminating a block, the ending memory - * state to stop encoding; there will be a helper function to - * assist in creating this value for a given set of inputs; - * default is the "all zero" state. - */ - -class gr_streams_encode_convolutional; -typedef boost::shared_ptr - gr_streams_encode_convolutional_sptr; - -gr_streams_encode_convolutional_sptr -gr_make_streams_encode_convolutional -(int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination = true, - int start_memory_state = 0, - int end_memory_state = 0); - -gr_streams_encode_convolutional_sptr -gr_make_streams_encode_convolutional_feedback -(int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - const std::vector &code_feedback, - bool do_termination = true, - int start_memory_state = 0, - int end_memory_state = 0); - -class gr_streams_encode_convolutional : public gr_block -{ - friend gr_streams_encode_convolutional_sptr - gr_make_streams_encode_convolutional - (int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination, - int start_memory_state, - int end_memory_state); - - friend gr_streams_encode_convolutional_sptr - gr_make_streams_encode_convolutional_feedback - (int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - const std::vector &code_feedback, - bool do_termination, - int start_memory_state, - int end_memory_state); - - gr_streams_encode_convolutional (int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination, - int start_memory_state, - int end_memory_state); - - gr_streams_encode_convolutional (int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - const std::vector &code_feedback, - bool do_termination, - int start_memory_state, - int end_memory_state); - - void setup_io_signatures (int n_code_inputs, int n_code_outputs); - - encoder_convolutional_ic1_ic1* d_encoder; - -public: - ~gr_streams_encode_convolutional (); - - inline encoder_convolutional_ic1_ic1* encoder () {return (d_encoder);}; - - virtual void forecast (int noutput_items, - gr_vector_int &ninput_items_required); - - virtual int general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* INCLUDED_GR_STREAMS_ENCODE_CONVOLUTIONAL_H */ diff --git a/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.i b/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.i deleted file mode 100644 index 63d60c6de..000000000 --- a/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.i +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -GR_SWIG_BLOCK_MAGIC(gr,streams_encode_convolutional); - -// Rename second constructor -%rename(streams_encode_convolutional_feedback) gr_make_streams_encode_convolutional_feedback; - -// support vectors of these ... for use in the convolutional decoder -// as well as Turbo Codes (both encoder and decoder). - -namespace std { - %template(x_vector_gr_streams_encode_convolutional_sptr) vector; -}; - -gr_streams_encode_convolutional_sptr -gr_make_streams_encode_convolutional -(int block_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination = true, - int start_memory_state = 0, - int end_memory_state = 0); - -gr_streams_encode_convolutional_sptr -gr_make_streams_encode_convolutional_feedback -(int block_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - const std::vector &code_feedback, - bool do_termination = true, - int start_memory_state = 0, - int end_memory_state = 0); - -class gr_streams_encode_convolutional : public gr_block -{ -private: - gr_streams_encode_convolutional - (int block_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - bool do_termination, - int start_memory_state, - int end_memory_state); - - gr_streams_encode_convolutional - (int block_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generator, - const std::vector &code_feedback, - bool do_termination, - int start_memory_state, - int end_memory_state); -}; diff --git a/gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.cc b/gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.cc deleted file mode 100644 index 9d7f72fe6..000000000 --- a/gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.cc +++ /dev/null @@ -1,209 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -gr_streams_encode_turbo_sptr -gr_make_streams_encode_turbo -(int n_code_inputs, - int n_code_outputs, - const std::vector &encoders, - const std::vector &interleavers) -{ - return gr_streams_encode_turbo_sptr - (new gr_streams_encode_turbo (n_code_inputs, - n_code_outputs, - encoders, - interleavers)); -} - -gr_streams_encode_turbo::gr_streams_encode_turbo -(int n_code_inputs, - int n_code_outputs, - const std::vector &encoders, - const std::vector &interleavers) - : gr_block ("streams_encode_turbo", - 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. - - // check out individual encoders, to make sure the total input / - // output matches those specified by the user. - - d_n_encoders = encoders.size (); - - if (d_n_encoders < 2) { - std::cerr << "gr_streams_encode_turbo: Error: " - "too few (" << d_n_encoders << ") encoders specified; a Turbo " - "code requires at least 2 constituent encoders.\n"; - assert (0); - } - - // make sure that the block size and termination are consistent for - // all encoders; warn the user if not, since it doesn't really - // matter to the encoder (but it might to the decoder; remains to be - // seen). - - encoder_convolutional_ic1_ic1* t_ec = encoders[0]->encoder (); - d_block_size_bits = t_ec->block_size_bits (); - d_do_termination = t_ec->do_termination (); - bool t_diff_block_size, t_diff_termination; - t_diff_block_size = t_diff_termination = false; - - for (size_t m = 1; m < d_n_encoders; m++) { - t_ec = encoders[0]->encoder (); - size_t t_block_size_bits = t_ec->block_size_bits (); - if (t_block_size_bits != d_block_size_bits) - t_diff_block_size = true; - bool t_do_termination = t_ec->do_termination (); - if (t_do_termination != d_do_termination) - t_do_termination = true; - } - - if (t_diff_block_size == true) { - std::cout << "gr_streams_encode_turbo: Warning: " - "Some constituent encoders have different block size (bits).\n"; - } - if (t_diff_termination == true) { - std::cout << "gr_streams_encode_turbo: Warning: " - "Some constituent encoders are differently terminationed.\n"; - } - - std::cout << "gr_streams_encode_turbo: setup:\n" - "d_n_encoders = " << d_n_encoders << "\n" - "n_code_inputs = " << n_code_inputs << "\n" - "n_code_outputs = " << n_code_outputs << "\n\n" - "Individual Encoders:\n"; - - for (size_t m = 0; m < d_n_encoders; m++) { - t_ec = encoders[m]->encoder (); - std::cout << " [" << (m+1) << "]:\n" - "n_code_inputs = " << (t_ec->n_code_inputs()) << "\n" - "n_code_outputs = " << (t_ec->n_code_outputs()) << "\n" - "block_size_bits = " << (t_ec->block_size_bits()) << "\n" - "do_termination = " << - ((t_ec->do_termination()==true)?"true":"false") << "\n"; - } - -#if 1 - assert (0); -#else - if (d_n_encoders != (interleavers.size())) {} - - d_encoder = new encoder_turbo_ic1_ic1 (n_code_inputs, - n_code_outputs, - code_generators, - do_termination, - start_memory_state, - end_memory_state); -#endif - - // create the correct input signature; 1 bit per input char - - set_input_signature (gr_make_io_signature (n_code_inputs, - n_code_inputs, - sizeof (char))); - - // create the correct output signature; 1 bit per output char - - set_output_signature (gr_make_io_signature (n_code_outputs, - n_code_outputs, - sizeof (char))); - -// set the output multiple to 1 item, then let the encoder class -// handle the rest internally - - set_output_multiple (1); -} - -gr_streams_encode_turbo::~gr_streams_encode_turbo -() -{ - if (d_encoder) - delete d_encoder; -} - -/* - * Compute the number of input bits (items in this case, since each - * item has 1 bit in it) needed to produce 'n_output' bits (items in - * this case, since each item has 1 bit in it). - * - * For turbo encoders, there is 1 bit output per bit input per - * stream, with the addition of a some bits for trellis termination if - * selected. Thus the input:output bit ratio will be: - * - * if (streaming | no termination), 1:1 - * - * if (not streaming & termination), roughly 1:(1+X), where "X" is the - * total memory size of the code divided by the block length in bits. - * But this also depends on the state of the FSM ... how many bits are - * left before termination. - */ - -void gr_streams_encode_turbo::forecast -(int noutput_items, - gr_vector_int &ninput_items_required) -{ - int ninput_items = d_encoder->compute_n_input_bits (noutput_items); - size_t ninputs = ninput_items_required.size(); - for (size_t n = 0; n < ninputs; n++) - ninput_items_required[n] = ninput_items; -} - -int -gr_streams_encode_turbo::general_work -(int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - // FIXME: 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); - 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)); - - // "work" is handled by the encoder; which returns the actual number - // of input items (1-bit char's) used. - - t_n_input_items = d_encoder->encode ((const char **)(&input_items[0]), - (char **)(&output_items[0]), - (size_t) noutput_items); - - // consume the number of used input items on all input streams - - consume_each (t_n_input_items); - - // returns number of items written to each output stream - - return (noutput_items); -} diff --git a/gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.h b/gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.h deleted file mode 100644 index 942772489..000000000 --- a/gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef INCLUDED_GR_STREAMS_ENCODE_TURBO_H -#define INCLUDED_GR_STREAMS_ENCODE_TURBO_H - -#include -#include - -#if 0 -#include -#else -#include -#endif - -/*! - * \brief Encode the incoming stream(s) using a turbo encoder - * - * input: streams of char, one stream per input as defined by the - * instantiated code, using only the right-most justified bit as - * the single input bit per input item. - * - * output: streams of char, one stream per output as defined by the - * instantiated code, using only the right-most justified bit as - * the single output bit per output item. - * - * n_code_inputs: - * n_code_outputs: the total number of code inputs and outputs for the - * overall turbo encoder (not just the constituent codes). - * - * encoders: the constituent encoders to be used; all -should- be - * configured with the same "block_size" and "termination", though - * from this encoder's perspective it doesn't really matter. - * - * interleavers: the interleavers to use before each encoder, - * respectively, except the first encoder which will not use an - * interleaver. - */ - -class gr_streams_encode_turbo; - -typedef boost::shared_ptr -gr_streams_encode_turbo_sptr; - -gr_streams_encode_turbo_sptr -gr_make_streams_encode_turbo -(int n_code_inputs, - int n_code_outputs, - const std::vector &encoders, - const std::vector &interleavers); - -class gr_streams_encode_turbo : public gr_block -{ - friend gr_streams_encode_turbo_sptr - gr_make_streams_encode_turbo - (int n_code_inputs, - int n_code_outputs, - const std::vector &d_encoders, - const std::vector &d_interleavers); - - gr_streams_encode_turbo - (int n_code_inputs, - int n_code_outputs, - const std::vector &d_encoders, - const std::vector &d_interleavers); - - std::vector d_encoders; - std::vector d_interleavers; - size_t d_n_encoders, d_block_size_bits; - bool d_do_termination; - encoder_turbo* d_encoder; - -public: - ~gr_streams_encode_turbo (); - - virtual void forecast (int noutput_items, - gr_vector_int &ninput_items_required); - - virtual int general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* INCLUDED_GR_STREAMS_ENCODE_TURBO_H */ diff --git a/gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.i b/gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.i deleted file mode 100644 index 59ca5c51e..000000000 --- a/gr-error-correcting-codes/src/lib/gr_streams_encode_turbo.i +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -GR_SWIG_BLOCK_MAGIC(gr,streams_encode_turbo); - -#include - -gr_streams_encode_turbo_sptr -gr_make_streams_encode_turbo -(int n_code_inputs, - int n_code_outputs, - const std::vector &encoders, - const std::vector &interleavers); - -class gr_streams_encode_turbo : public gr_block -{ - gr_streams_encode_turbo - (int frame_size_bits, - int n_code_inputs, - const std::vector &encoders, - const std::vector &interleavers); -}; diff --git a/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.cc b/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.cc deleted file mode 100644 index 7a1230960..000000000 --- a/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.cc +++ /dev/null @@ -1,167 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -gr_syms_to_metrics_sptr -gr_make_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit, - gr_feval_ff* pdf_fcn_1_bit, - int n_samples, - float min_sample, - float max_sample, - int sample_precision) -{ - return gr_syms_to_metrics_sptr - (new gr_syms_to_metrics (pdf_fcn_0_bit, - pdf_fcn_1_bit, - n_samples, - min_sample, - max_sample, - sample_precision)); -} - -/* - * dummy functions and variables to get the float(*)(float) function - * to work properly with the gr_feval_XX stuff. - */ - -static gr_feval_ff* l_pdf_fcn_0_bit; -static gr_feval_ff* l_pdf_fcn_1_bit; - -static float pdf_fcn_0 (float x) -{ - return (l_pdf_fcn_0_bit->eval (x)); -} - -static float pdf_fcn_1 (float x) -{ - return (l_pdf_fcn_1_bit->eval (x)); -} - -gr_syms_to_metrics::gr_syms_to_metrics -(gr_feval_ff* pdf_fcn_0_bit, - gr_feval_ff* pdf_fcn_1_bit, - int n_samples, - float min_sample, - float max_sample, - int sample_precision) - : gr_block ("syms_to_metrics", - gr_make_io_signature (1, -1, sizeof (float)), - gr_make_io_signature (0, 0, 0)) -{ - if ((sample_precision < 0) | (sample_precision > 32)) { - fprintf (stderr, "gr_syms_to_metrics: sample_precision must be " - " between 0 and 32.\n"); - assert (0); - } - - l_pdf_fcn_0_bit = pdf_fcn_0_bit; - l_pdf_fcn_1_bit = pdf_fcn_1_bit; - - if (sample_precision == 0) { - // float - d_out_item_size_bytes = sizeof (float); - d_code_metrics = new code_metric_ff (&pdf_fcn_0, - &pdf_fcn_1, - n_samples, - min_sample, - max_sample); - } else if (sample_precision <= 8) { - // use char - d_out_item_size_bytes = sizeof (char); - d_code_metrics = new code_metric_fb (&pdf_fcn_0, - &pdf_fcn_1, - n_samples, - min_sample, - max_sample, - sample_precision); - } else if (sample_precision <= 16) { - // use short - d_out_item_size_bytes = sizeof (short); - d_code_metrics = new code_metric_fs (&pdf_fcn_0, - &pdf_fcn_1, - n_samples, - min_sample, - max_sample, - sample_precision); - } else { - // use long - d_out_item_size_bytes = sizeof (long); - d_code_metrics = new code_metric_fl (&pdf_fcn_0, - &pdf_fcn_1, - n_samples, - min_sample, - max_sample, - sample_precision); - } - - set_output_signature (gr_make_io_signature (1, -1, d_out_item_size_bytes)); -} - -bool gr_syms_to_metrics::check_topology (int ninputs, int noutputs) -{ - return ((noutputs == (2*ninputs)) ? true : false); -} - -void -gr_syms_to_metrics::forecast -(int noutput_items, - gr_vector_int &ninput_items_required) -{ - // always 1:1, for all streams - for (size_t n = 0; n < ninput_items_required.size(); n++) { - ninput_items_required[n] = noutput_items; - } -} - -int -gr_syms_to_metrics::general_work -(int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - size_t l_n_output_items = noutput_items; - - for (size_t n = 0; n < input_items.size(); n++) { - float* t_in_buf = (float*)(&input_items[n]); - void* t_out_buf_0_bit = (void*)(&(output_items[2*n])); - void* t_out_buf_1_bit = (void*)(&(output_items[(2*n)+1])); - - d_code_metrics->convert (l_n_output_items, t_in_buf, - t_out_buf_0_bit, t_out_buf_1_bit); - } - - // consume the number of used input items on all input streams - - consume_each (noutput_items); - - // returns number of items written to each output stream - - return (noutput_items); -} diff --git a/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.h b/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.h deleted file mode 100644 index d084fde81..000000000 --- a/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.h +++ /dev/null @@ -1,121 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef INCLUDED_SYMS_TO_METRICS_H -#define INCLUDED_SYMS_TO_METRICS_H - -#include -#include -#include -#include - -class gr_syms_to_metrics; -typedef boost::shared_ptr gr_syms_to_metrics_sptr; - -gr_syms_to_metrics_sptr gr_make_syms_to_metrics -(gr_feval_ff* pdf_fcn_0_bit, - gr_feval_ff* pdf_fcn_1_bit, - int n_samples, - float min_sample, - float max_sample, - int sample_precision); - -/*! - * \brief Convert the input stream(s) of soft (float) symbols to - * log-probability metrics of user-specified precision; output is 2 - * streams per input stream, each stream consisting of the metric for - * receiving a 0-bit and 1-bit, respectively, with the lower-numbered - * stream being the 0-bit. - * - * input: stream(s) of float; output: stream(s) of metrics - */ - -class gr_syms_to_metrics : public gr_block -{ - friend gr_syms_to_metrics_sptr - gr_make_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit, - gr_feval_ff* pdf_fcn_1_bit, - int n_samples, - float min_sample, - float max_sample, - int sample_precision); - -/* - * gr_syms_to_metrics: Convert the input soft (float) symbols into - * log-probabilities (metrics) for use in the convolutional - * decoder. Samples the provided PDF function in 'n_samples' - * places from 'min_sample' to 'max_sample', takes the log of that - * value, then converts the result into a given precision and - * stores all results in a "handy dandy" lookup table for much - * faster processing. - * - * pdf_fcn_0_bit: point to a probability distribution function which - * takes a float and returns a float, for the 0-bit probabilities. - * - * pdf_fcn_1_bit: point to a probability distribution function which - * takes a float and returns a float, for the 1-bit probabilities. - * - * n_samples: the number of samples between min_sample and max_sample - * to store in the lookup table. Must be at least 2, but - * otherwise is limited only by the amount of available memory; - * generally, 65536 (1 << 16) is plenty of samples. - * - * min_sample: the minimum value below which any incoming value is - * "rounded" up. - * - * max_sample: the maximum value above which any incoming value is - * "rounded" down. - * - * sample_precision: the precision with which to sample the returned - * value of the PDF function. - * + Cannot be < 0 or > 32. - * + "soft float" == 0 - * + otherwise, convert to an integer of the given value - * - * in "work", finds the (linearly) closest sample value for the given - * input and outputs the metric for a 0-bit input on the first - * stream and a 1-bit input on the second stream. - * - */ - - gr_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit, - gr_feval_ff* pdf_fcn_1_bit, - int n_samples, - float min_sample, - float max_sample, - int sample_precision); - - size_t d_out_item_size_bytes; - code_metrics* d_code_metrics; - -public: - bool check_topology (int ninputs, int noutputs); - - void forecast (int noutput_items, gr_vector_int &ninput_items_required); - - int general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); -}; - -#endif /* INCLUDED_SYMS_TO_METRICS_H */ diff --git a/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.i b/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.i deleted file mode 100644 index 6a76a7140..000000000 --- a/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.i +++ /dev/null @@ -1,41 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -GR_SWIG_BLOCK_MAGIC(gr,syms_to_metrics); - -gr_syms_to_metrics_sptr gr_make_syms_to_metrics -(gr_feval_ff* pdf_fcn_0_bit, - gr_feval_ff* pdf_fcn_1_bit, - int n_samples, - float min_sample, - float max_sample, - int sample_precision); - -class gr_syms_to_metrics : public gr_block -{ - gr_syms_to_metrics (gr_feval_ff* pdf_fcn_0_bit, - gr_feval_ff* pdf_fcn_1_bit, - int n_samples, - float min_sample, - float max_sample, - int sample_precision); -}; diff --git a/gr-error-correcting-codes/src/lib/libecc/Makefile.am b/gr-error-correcting-codes/src/lib/libecc/Makefile.am index e2fa9eca5..95e760253 100644 --- a/gr-error-correcting-codes/src/lib/libecc/Makefile.am +++ b/gr-error-correcting-codes/src/lib/libecc/Makefile.am @@ -23,31 +23,27 @@ include $(top_srcdir)/Makefile.common SUBDIRS = mld . tests -INCLUDES = $(STD_DEFINES_AND_INCLUDES) -I.. +INCLUDES = $(STD_DEFINES_AND_INCLUDES) -I$(top_srcdir)/gr-error-correcting-codes/src/lib noinst_LTLIBRARIES = libecc.la libecc_la_SOURCES = \ code_convolutional_trellis.cc \ - code_metrics.cc \ + code_metrics.cc code_io.cc \ encoder.cc \ encoder_convolutional.cc \ - encoder_convolutional_ic1_ic1.cc \ encoder_turbo.cc \ decoder.cc \ decoder_viterbi.cc \ - decoder_viterbi_full_block.cc \ - decoder_viterbi_full_block_i1_ic1.cc + decoder_viterbi_full_block.cc noinst_HEADERS = \ - code_types.h code_metrics.h \ + code_types.h code_metrics.h code_io.h \ code_convolutional_trellis.h \ encoder.h encoder_turbo.h \ encoder_convolutional.h \ - encoder_convolutional_ic1_ic1.h \ decoder.h decoder_viterbi.h \ - decoder_viterbi_full_block.h \ - decoder_viterbi_full_block_i1_ic1.h + decoder_viterbi_full_block.h # link the library against the c++ standard library libecc_la_LIBADD = \ diff --git a/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.cc b/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.cc index 72b8adbf7..c04fafaec 100644 --- a/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.cc +++ b/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.cc @@ -29,8 +29,8 @@ #include #define DO_TIME_THOUGHPUT 0 -#define DO_PRINT_DEBUG 1 -#define DO_PRINT_DEBUG_ENCODE 1 +#define DO_PRINT_DEBUG 0 +#define DO_PRINT_DEBUG_ENCODE 0 #include #include @@ -285,7 +285,8 @@ code_convolutional_trellis::code_convolutional_trellis_init // store the parameters for SOAI - std::vector t_fb_generators_soai, t_n_delays_soai, t_io_num_soai; + std::vector t_fb_generators_soai; + std::vector t_n_delays_soai, t_io_num_soai; std::vector t_states_ndx_soai; size_t t_max_delay_soai, t_total_n_delays_soai, t_n_memories_soai; @@ -554,23 +555,21 @@ code_convolutional_trellis::create_trellis for (size_t m = 0; m < d_n_states; m++) { d_trellis[m].resize (d_n_input_combinations); - for (size_t n = 0; n < d_n_input_combinations; n++) { - connection_t_ptr t_connection = &(d_trellis[m][n]); - t_connection->d_output_bits.resize (d_n_code_outputs); - } } // fill in the trellis - for (size_t m = 0; m < d_n_states; m++) { - for (size_t n = 0; n < d_n_input_combinations; n++) { + for (memory_t m = 0; m < d_n_states; m++) { + for (memory_t n = 0; n < d_n_input_combinations; n++) { connection_t_ptr t_connection = &(d_trellis[m][n]); encode_single (m, n, t_connection->d_to_state, t_connection->d_output_bits); if (DO_PRINT_DEBUG_ENCODE) { std::cout << "set d_t[" << n2bs(m,d_total_n_delays) << "][" << n2bs(n,d_n_code_inputs) << "] : to_st = " << - n2bs(t_connection->d_to_state,d_total_n_delays) << "\n"; + n2bs(t_connection->d_to_state,d_total_n_delays) << + ", o_b = " << n2bs(t_connection->d_output_bits,d_n_code_outputs) << + "\n"; } } } @@ -641,12 +640,34 @@ code_convolutional_trellis::mux_inputs return (inputs); } +void +code_convolutional_trellis::demux_outputs +(memory_t outputs, + std::vector& out_vec) +{ + for (size_t m = 0; m < d_n_code_outputs; m++, outputs >>= 1) { + out_vec[m] = (char)(outputs & 1); + } +} + +memory_t +code_convolutional_trellis::mux_outputs +(const std::vector& out_vec) +{ + size_t bit_shift = 0; + memory_t outputs = 0; + for (size_t m = 0; m < out_vec.size(); m++, bit_shift++) { + outputs |= (((memory_t)(out_vec[m]&1)) << bit_shift); + } + return (outputs); +} + void code_convolutional_trellis::encode_single (memory_t in_state, - size_t inputs, + memory_t inputs, memory_t& out_state, - std::vector& out_bits) + memory_t& out_bits) { // set input parameters @@ -672,42 +693,45 @@ code_convolutional_trellis::encode_single // retrieve the output parameters out_state = mux_state (d_memory); - out_bits = d_current_outputs; + out_bits = mux_outputs (d_current_outputs); } void code_convolutional_trellis::encode_lookup (memory_t& state, const std::vector& inputs, - std::vector& out_bits) + memory_t& out_bits) { - if (DO_PRINT_DEBUG_ENCODE) { - std::cout << "using d_t[" << state << "][" << mux_inputs(inputs) << - "] = "; - std::cout.flush (); - } - connection_t_ptr t_connection = &(d_trellis[state][mux_inputs(inputs)]); - - if (DO_PRINT_DEBUG_ENCODE) { - std::cout << t_connection << ": to_state = " - << t_connection->d_to_state << "\n"; - } - state = t_connection->d_to_state; out_bits = t_connection->d_output_bits; } +void +code_convolutional_trellis::encode_lookup +(memory_t& state, + const std::vector& inputs, + std::vector& out_bits) +{ + connection_t_ptr t_connection = &(d_trellis[state][mux_inputs(inputs)]); + state = t_connection->d_to_state; + demux_outputs (t_connection->d_output_bits, out_bits); +} + void code_convolutional_trellis::get_termination_inputs (memory_t term_start_state, size_t bit_num, std::vector& inputs) { - inputs.resize (d_n_code_inputs); +#if 1 + // for now, just assign all 0's + inputs.assign (d_n_code_inputs, 0); +#else for (size_t m = 0; m < d_n_code_inputs; m++) { inputs[m] = ((d_term_inputs[term_start_state][m]) >> bit_num) & 1; } +#endif } void diff --git a/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.h b/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.h index 205ccc03d..3aee1a0a6 100644 --- a/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.h +++ b/gr-error-correcting-codes/src/lib/libecc/code_convolutional_trellis.h @@ -32,12 +32,12 @@ * * d_to_state: memory configuration of the "to" state * - * d_output_bits: the output bits for this connection + * d_output_bits: the output bits for this connection, mux'ed */ typedef struct connection_t { memory_t d_to_state; - std::vector d_output_bits; + memory_t d_output_bits; } connection_t, *connection_t_ptr; /* @@ -152,9 +152,11 @@ public: /* for remote access to internal info */ - inline size_t block_size_bits () {return (d_block_size_bits);}; - inline size_t n_code_inputs () {return (d_n_code_inputs);}; - inline size_t n_code_outputs () {return (d_n_code_outputs);}; + inline const size_t block_size_bits () {return (d_block_size_bits);}; + inline const size_t n_code_inputs () {return (d_n_code_inputs);}; + inline const size_t n_code_outputs () {return (d_n_code_outputs);}; + inline const size_t n_states () {return (d_n_states);}; + inline const size_t n_input_combinations () {return (d_n_input_combinations);}; inline const bool do_termination () {return (d_do_termination);}; inline const bool do_feedback () {return (d_do_feedback);}; inline const bool do_streaming () {return (d_do_streaming);}; @@ -165,14 +167,25 @@ public: size_t bit_num, std::vector& 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. + + void encode_lookup (memory_t& state, + const std::vector& inputs, + memory_t& out_bits); void encode_lookup (memory_t& state, const std::vector& inputs, std::vector& out_bits); + // methods for setting and retrieving the state, inputs, and outputs. + void demux_state (memory_t in_state, std::vector& memories); memory_t mux_state (const std::vector& memories); void demux_inputs (memory_t inputs, std::vector& in_vec); memory_t mux_inputs (const std::vector& in_vec); + void demux_outputs (memory_t outputs, std::vector& out_vec); + memory_t mux_outputs (const std::vector& out_vec); protected: #if 0 @@ -267,7 +280,7 @@ protected: void encode_single (memory_t in_state, memory_t inputs, memory_t& out_state, - std::vector& out_bits); + memory_t& out_bits); virtual void encode_single_soai (); virtual void encode_single_siao (); virtual void encode_single_soai_fb (); diff --git a/gr-error-correcting-codes/src/lib/libecc/code_io.cc b/gr-error-correcting-codes/src/lib/libecc/code_io.cc new file mode 100644 index 000000000..e25309069 --- /dev/null +++ b/gr-error-correcting-codes/src/lib/libecc/code_io.cc @@ -0,0 +1,33 @@ +/* -*- 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 + +#define DO_PRINT_DEBUG 0 + +static const int g_num_bits_per_byte = 8; + +// nothing yet ... it's all in the header file for now. diff --git a/gr-error-correcting-codes/src/lib/libecc/code_io.h b/gr-error-correcting-codes/src/lib/libecc/code_io.h new file mode 100644 index 000000000..1147db51f --- /dev/null +++ b/gr-error-correcting-codes/src/lib/libecc/code_io.h @@ -0,0 +1,556 @@ +/* -*- 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_IO_H +#define INCLUDED_CODE_IO_H + +#include "code_types.h" +#include +#include +#include + +/* + * code_io provides classes which do the input and output for these + * codes. One can add another class with its specific needs primarily + * by changing the way that the provided data is manipulated to read + * or write data items. + */ + +/* + * combined io classes + */ + +class code_io +{ +public: + inline code_io (size_t n_streams) { + if (n_streams < 1) { + std::cerr << "code_io::code_io: Error:" << + "Provided # of streams (" << n_streams << + ") must be at least 1.\n"; + assert (0); + } + d_n_streams = n_streams; + d_buf_ptrs.resize (d_n_streams); + }; + + virtual ~code_io () {}; + + inline void set_buffer (void** buffer, size_t n_items) { + if (buffer == 0) { + std::cerr << "code_io::set_buffer: Error:" << + "Provided buffer is NULL.\n"; + assert (0); + } + if (n_items == 0) { + std::cerr << "code_io::set_buffer: Warning:" << + "Provided # of items is 0!\n"; + } + d_buf = buffer; + d_n_items = d_n_items_left = n_items; + for (size_t m = 0; m < d_n_streams; m++) { + d_buf_ptrs[m] = d_buf[m]; + } + }; + + inline void set_buffer (std::vector* buffer, size_t n_items) { + set_buffer (&((*buffer)[0]), n_items);}; + + inline void set_buffer (std::vector& buffer, size_t n_items) { + set_buffer (&(buffer[0]), n_items);}; + + inline virtual void increment_indices () { + if (d_n_items_left == 0) { + std::cerr << "code_io::increment_indices: Warning: " + "No items left!\n"; + } else + d_n_items_left--; + }; + + // methods for getting info on class internals + + const size_t& n_items_left () {return (d_n_items_left);}; + const size_t n_items_used () {return (d_n_items - d_n_items_left);}; + const size_t n_streams () {return (d_n_streams);}; + +protected: + void** d_buf; + std::vector d_buf_ptrs; + size_t d_n_streams, d_n_items, d_n_items_left; +}; + +/* + * input classes + */ + +class code_input : public code_io +{ +public: + inline code_input (size_t n_streams) : code_io (n_streams) {}; + virtual ~code_input () {}; + virtual void read_item (void* item, size_t stream_n) = 0; + virtual void read_items (void* items) = 0; + inline virtual void increment_indices () {code_io::increment_indices ();}; +}; + +typedef code_input* code_input_ptr; + +class code_input_id : public code_input +{ +private: + typedef double input_t; + +public: +/*! + * class code_input_id : public code_input + * + * "id": + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 'f': streams of double; + */ + inline code_input_id (size_t n_streams) : code_input (n_streams) {}; + virtual ~code_input_id () {}; + + inline virtual void read_item (void* item, size_t stream_n) { + /* no error checking for better speed! */ + input_t* t_item = (input_t*) item; + (*t_item) = (*((input_t*)(d_buf_ptrs[stream_n]))); + }; + inline virtual void read_items (void* items) { + /* no error checking for better speed! */ + input_t* t_items = (input_t*) items; + for (size_t m = 0; m < d_n_streams; m++) { + t_items[m] = (*((input_t*)(d_buf_ptrs[m]))); + } + }; + inline virtual void increment_indices () { + code_input::increment_indices (); + for (size_t m = 0; m < d_n_streams; m++) { + input_t* t_buf = (input_t*) d_buf_ptrs[m]; + d_buf_ptrs[m] = (void*)(++t_buf); + } + }; +}; + +class code_input_if : public code_input +{ +private: + typedef float input_t; + +public: +/*! + * class code_input_if : public code_input + * + * "if": + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 'f': streams of float; + */ + inline code_input_if (size_t n_streams) : code_input (n_streams) {}; + virtual ~code_input_if () {}; + + inline virtual void read_item (void* item, size_t stream_n) { + /* no error checking for better speed! */ + input_t* t_item = (input_t*) item; + (*t_item) = (*((input_t*)(d_buf_ptrs[stream_n]))); + }; + inline virtual void read_items (void* items) { + /* no error checking for better speed! */ + input_t* t_items = (input_t*) items; + for (size_t m = 0; m < d_n_streams; m++) { + t_items[m] = (*((input_t*)(d_buf_ptrs[m]))); + } + }; + inline virtual void increment_indices () { + code_input::increment_indices (); + for (size_t m = 0; m < d_n_streams; m++) { + input_t* t_buf = (input_t*) d_buf_ptrs[m]; + d_buf_ptrs[m] = (void*)(++t_buf); + } + }; +}; + +class code_input_ic : public code_input +{ +private: + typedef char input_t; + +public: +/*! + * class code_input_is : public code_input + * + * "ic": + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 'c': streams of char; + */ + inline code_input_ic (size_t n_streams) : code_input (n_streams) {}; + virtual ~code_input_ic () {}; + + inline virtual void read_item (void* item, size_t stream_n) { + /* no error checking for better speed! */ + input_t* t_item = (input_t*) item; + (*t_item) = (*((input_t*)(d_buf_ptrs[stream_n]))); + }; + inline virtual void read_items (void* items) { + /* no error checking for better speed! */ + input_t* t_items = (input_t*) items; + for (size_t m = 0; m < d_n_streams; m++) { + t_items[m] = (*((input_t*)(d_buf_ptrs[m]))); + } + }; + inline virtual void increment_indices () { + code_input::increment_indices (); + for (size_t m = 0; m < d_n_streams; m++) { + input_t* t_buf = (input_t*) d_buf_ptrs[m]; + d_buf_ptrs[m] = (void*)(++t_buf); + } + }; +}; + +class code_input_is : public code_input +{ +private: + typedef short input_t; + +public: +/*! + * class code_input_is : public code_input + * + * "is": + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 's': streams of short; + */ + inline code_input_is (size_t n_streams) : code_input (n_streams) {}; + virtual ~code_input_is () {}; + + inline virtual void read_item (void* item, size_t stream_n) { + /* no error checking for better speed! */ + input_t* t_item = (input_t*) item; + (*t_item) = (*((input_t*)(d_buf_ptrs[stream_n]))); + }; + inline virtual void read_items (void* items) { + /* no error checking for better speed! */ + input_t* t_items = (input_t*) items; + for (size_t m = 0; m < d_n_streams; m++) { + t_items[m] = (*((input_t*)(d_buf_ptrs[m]))); + } + }; + inline virtual void increment_indices () { + code_input::increment_indices (); + for (size_t m = 0; m < d_n_streams; m++) { + input_t* t_buf = (input_t*) d_buf_ptrs[m]; + d_buf_ptrs[m] = (void*)(++t_buf); + } + }; +}; + +class code_input_il : public code_input +{ +private: + typedef long input_t; + +public: +/*! + * class code_input_il : public code_input + * + * "il": + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 'l': streams of long; + */ + inline code_input_il (size_t n_streams) : code_input (n_streams) {}; + virtual ~code_input_il () {}; + + inline virtual void read_item (void* item, size_t stream_n) { + /* no error checking for better speed! */ + input_t* t_item = (input_t*) item; + (*t_item) = (*((input_t*)(d_buf_ptrs[stream_n]))); + }; + inline virtual void read_items (void* items) { + /* no error checking for better speed! */ + input_t* t_items = (input_t*) items; + for (size_t m = 0; m < d_n_streams; m++) { + t_items[m] = (*((input_t*)(d_buf_ptrs[m]))); + } + }; + inline virtual void increment_indices () { + code_input::increment_indices (); + for (size_t m = 0; m < d_n_streams; m++) { + input_t* t_buf = (input_t*) d_buf_ptrs[m]; + d_buf_ptrs[m] = (void*)(++t_buf); + } + }; +}; + +class code_input_ill : public code_input +{ +private: + typedef long long input_t; + +public: +/*! + * class code_input_ill : public code_input + * + * "ill": + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 'll': streams of long long; + */ + inline code_input_ill (size_t n_streams) : code_input (n_streams) {}; + virtual ~code_input_ill () {}; + + inline virtual void read_item (void* item, size_t stream_n) { + /* no error checking for better speed! */ + input_t* t_item = (input_t*) item; + (*t_item) = (*((input_t*)(d_buf_ptrs[stream_n]))); + }; + inline virtual void read_items (void* items) { + /* no error checking for better speed! */ + input_t* t_items = (input_t*) items; + for (size_t m = 0; m < d_n_streams; m++) { + t_items[m] = (*((input_t*)(d_buf_ptrs[m]))); + } + }; + inline virtual void increment_indices () { + code_input::increment_indices (); + for (size_t m = 0; m < d_n_streams; m++) { + input_t* t_buf = (input_t*) d_buf_ptrs[m]; + d_buf_ptrs[m] = (void*)(++t_buf); + } + }; +}; + +class code_input_ic1 : public code_input +{ +public: +/*! + * class code_input_ic1 : public code_input + * + * "ic": + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 'c': streams of char; + * '1': single bit per char; + * --> which bit to choose left to an inheriting class + */ + + inline code_input_ic1 (size_t n_streams) : code_input (n_streams) {}; + virtual ~code_input_ic1 () {}; + + inline virtual void read_item (void* item, size_t stream_n) { + /* no error checking for better speed! */ + char* t_item = (char*) item; + (*t_item) = (*((char*)(d_buf_ptrs[stream_n]))) & d_which_bit; + }; + inline virtual void read_items (void* items) { + /* no error checking for better speed! */ + char* t_items = (char*) items; + for (size_t m = 0; m < d_n_streams; m++) { + t_items[m] = (*((char*)(d_buf_ptrs[m]))) & d_which_bit; + } + }; + inline virtual void increment_indices () { + code_input::increment_indices (); + for (size_t m = 0; m < d_n_streams; m++) { + char* t_buf = (char*) d_buf_ptrs[m]; + d_buf_ptrs[m] = (void*)(++t_buf); + } + }; + +protected: + char d_which_bit; +}; + +class code_input_ic1l : public code_input_ic1 +{ +public: +/*! + * class code_input_ic1l : public code_input_ic1 + * + * "ic1l": + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 'c': streams of char; + * '1': single bit per char; + * 'l': using only the LSB of the char. + */ + + inline code_input_ic1l (size_t n_streams) : + code_input_ic1 (n_streams) {d_which_bit = 1;}; + virtual ~code_input_ic1l () {}; +}; + +class code_input_ic1h : public code_input_ic1 +{ +public: +/*! + * class code_input_ic1h : public code_input_ic1 + * + * "ic1h": + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 'c': streams of char; + * '1': single bit per char; + * 'h': using only the MSB of the char. + */ + + inline code_input_ic1h (size_t n_streams) + : code_input_ic1 (n_streams) {d_which_bit = 128;}; + virtual ~code_input_ic1h () {}; +}; + +class code_input_ic8l : public code_input_ic1l +{ +protected: + size_t d_bit_shift; + const static size_t g_num_bits_per_byte = 8; + +public: +/*! + * class code_input_ic8l : public code_input_ic1l + * + * "ic8l": + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 'c': streams of char; + * '8': using all 8 bits per char; + * 'l': starting with the LSB and working up + */ + + inline code_input_ic8l (size_t n_streams) : + code_input_ic1l (n_streams) {d_bit_shift = 0;}; + + virtual ~code_input_ic8l () {}; + + inline virtual void increment_indices () { + code_input::increment_indices (); + if (++d_bit_shift % g_num_bits_per_byte == 0) { + d_bit_shift = 0; + for (size_t m = 0; m < d_n_streams; m++) { + char* t_buf = (char*) d_buf_ptrs[m]; + d_buf_ptrs[m] = (void*)(++t_buf); + } + } else { + for (size_t m = 0; m < d_n_streams; m++) { + char* t_buf = (char*) d_buf_ptrs[m]; + (*t_buf) >>= 1; + } + } + }; +}; + +class code_input_ic8h : public code_input_ic1h +{ +protected: + size_t d_bit_shift; + const static size_t g_num_bits_per_byte = 8; + +public: +/*! + * class code_input_ic8h : public code_input_ic1h + * + * "ic8h": + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 'c': streams of char; + * '8': using all 8 bits per char; + * 'h': starting with the MSB and working down + */ + + inline code_input_ic8h (size_t n_streams) : + code_input_ic1h (n_streams) {d_bit_shift = 0;}; + + virtual ~code_input_ic8h () {}; + + inline virtual void increment_indices () { + code_input::increment_indices (); + if (++d_bit_shift % g_num_bits_per_byte == 0) { + d_bit_shift = 0; + for (size_t m = 0; m < d_n_streams; m++) { + char* t_buf = (char*) d_buf_ptrs[m]; + d_buf_ptrs[m] = (void*)(++t_buf); + } + } else { + for (size_t m = 0; m < d_n_streams; m++) { + char* t_buf = (char*) d_buf_ptrs[m]; + (*t_buf) <<= 1; + } + } + }; +}; + +/* + * output classes + */ + +class code_output : public code_io +{ +public: + code_output (size_t n_streams) : code_io (n_streams) {}; + virtual ~code_output () {}; + virtual void write_item (const void* item, size_t stream_n) = 0; + virtual void write_items (const void* items) = 0; + virtual inline void increment_indices () {code_io::increment_indices ();}; +}; + +typedef code_output* code_output_ptr; + +class code_output_ic1l : public code_output +{ +public: +/*! + * class code_output_ic1l : public code_output + * + * 'i': one stream per code input as defined by the instantiated + * code ("individual", not mux'ed); + * 'c': streams of char; + * '1': single bit per char; + * 'l': using only the right-most justified (LSB). + */ + + inline code_output_ic1l (size_t n_streams) : code_output (n_streams) {}; + virtual ~code_output_ic1l () {}; + + inline virtual void write_item (const void* item, size_t stream_n) { + /* no error checking for better speed! */ + const char* t_item = (char*) item; + (*((char*)(d_buf_ptrs[stream_n]))) = (*t_item) & 1; + }; + inline virtual void write_items (const void* items) { + /* no error checking for better speed! */ + const char* t_items = (char*) items; + for (size_t m = 0; m < d_n_streams; m++) + (*((char*)(d_buf_ptrs[m]))) = (t_items[m]) & 1; + }; + inline virtual void increment_indices () { + code_output::increment_indices (); + for (size_t m = 0; m < d_n_streams; m++) { + char* t_buf = (char*) d_buf_ptrs[m]; + d_buf_ptrs[m] = (void*)(++t_buf); + } + }; +}; + +#endif /* INCLUDED_CODE_IO_H */ diff --git a/gr-error-correcting-codes/src/lib/libecc/code_metrics.cc b/gr-error-correcting-codes/src/lib/libecc/code_metrics.cc index 392450863..c1278498d 100644 --- a/gr-error-correcting-codes/src/lib/libecc/code_metrics.cc +++ b/gr-error-correcting-codes/src/lib/libecc/code_metrics.cc @@ -29,274 +29,261 @@ #include #include -code_metric_ff::code_metric_ff -(pdf_fcn_t pdf_fcn_0_bit, - pdf_fcn_t pdf_fcn_1_bit, +template +code_metrics_table* +libecc_code_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) + pdf_fcn_io_t max_sample, + int sample_precision) { - if (n_samples < 2) { - fprintf (stderr, "code_metric_f32:: n_samples " - "must be at least 2.\n"); + if (! pdf_fcn_0_bit) { + std::cerr << "libecc_code_metrics_create_table: Error: " + "pdf_fcn_0_bit must be a non-null pointer to function.\n"; assert (0); } - if (min_sample >= max_sample) { - fprintf (stderr, "code_metric_f32:: min_sample must be " - "less than max_sample.\n"); + if (! pdf_fcn_1_bit) { + std::cerr << "libecc_code_metrics_create_table: Error: " + "pdf_fcn_0_bit must be a non-null pointer to function.\n"; assert (0); } - if (! pdf_fcn_0_bit) { - fprintf (stderr, "code_metric_f32:: pdf_fcn_0_bit must be " - "a non-null pointer to function.\n"); + if (n_samples < 2) { + std::cerr << "libecc_code_metrics_create_table: Error: " + "n_samples must be at least 2.\n"; assert (0); } - if (! pdf_fcn_1_bit) { - fprintf (stderr, "code_metric_f32:: pdf_fcn_0_bit must be " - "a non-null pointer to function.\n"); + if (min_sample >= max_sample) { + std::cerr << "libecc_code_metrics_create_table: Error: " + "min_sample must be less than max_sample.\n"; assert (0); } - - d_n_samples = n_samples; - d_max_sample = max_sample; - d_min_sample = min_sample; - d_delta = (max_sample - min_sample) / (n_samples - 1); - d_pdf_fcn_0_bit = pdf_fcn_0_bit; - d_pdf_fcn_1_bit = pdf_fcn_1_bit; - d_metric_table_0_bit.assign (n_samples, 0); - d_metric_table_1_bit.assign (n_samples, 0); - - pdf_fcn_io_t l_val = min_sample; - for (size_t m = 0; m < n_samples; m++) { - d_metric_table_0_bit[m] = logf ((*pdf_fcn_0_bit)(l_val)); - d_metric_table_1_bit[m] = logf ((*pdf_fcn_1_bit)(l_val)); - l_val += d_delta; + if ((sample_precision < 0) | (sample_precision > 32)) { + std::cerr << "libecc_code_metrics_create_table: Error: " + "sample_precision must be between 0 and 32.\n"; + assert (0); } -} -void code_metric_ff::lookup -(pdf_fcn_io_t sym, - void* bit_0, - void* bit_1) -{ - metric_ptr_t l_bit_0 = (metric_ptr_t) bit_0; - metric_ptr_t l_bit_1 = (metric_ptr_t) bit_1; - - if (sym <= d_min_sample) { - *l_bit_0 = d_metric_table_0_bit[0]; - *l_bit_1 = d_metric_table_1_bit[0]; - return; - } - if (sym >= d_max_sample) { - *l_bit_0 = d_metric_table_0_bit.back (); - *l_bit_1 = d_metric_table_1_bit.back (); - return; + code_metrics_table* t_code_metrics_table; + + if (sample_precision == 0) { + // float + t_code_metrics_table = new code_metrics_table_work + (pdf_fcn_0_bit, + pdf_fcn_1_bit, + n_samples, + min_sample, + max_sample); + } else if (sample_precision <= 8) { + // use char + t_code_metrics_table = new code_metrics_table_work + (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_metrics_table = new code_metrics_table_work + (pdf_fcn_0_bit, + pdf_fcn_1_bit, + n_samples, + min_sample, + max_sample, + sample_precision); + } else { + // use long + t_code_metrics_table = new code_metrics_table_work + (pdf_fcn_0_bit, + pdf_fcn_1_bit, + n_samples, + min_sample, + max_sample, + sample_precision); } - size_t l_ndx = (size_t) roundf ((sym - d_min_sample) / d_delta); - *l_bit_0 = d_metric_table_0_bit[l_ndx]; - *l_bit_1 = d_metric_table_1_bit[l_ndx]; -} - -void code_metric_ff::convert -(size_t n_syms, - pdf_fcn_io_t* sym, - void* bit_0, - void* bit_1) -{ - metric_ptr_t l_bit_0 = (metric_ptr_t) bit_0; - metric_ptr_t l_bit_1 = (metric_ptr_t) bit_1; - - for (size_t m = n_syms; m > 0; m--) - lookup (*sym++, (void*) l_bit_0++, (void*) l_bit_1++); + return (t_code_metrics_table); } -code_metric_fl::code_metric_fl +template +code_metrics_table::code_metrics_table (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) + pdf_fcn_io_t max_sample) { - if (n_samples < 2) { - fprintf (stderr, "code_metric_fl:: n_samples " - "must be at least 2.\n"); - assert (0); - } - if (min_sample >= max_sample) { - fprintf (stderr, "code_metric_fl:: min_sample must be " - "less than max_sample.\n"); - assert (0); - } - if (! pdf_fcn_0_bit) { - fprintf (stderr, "code_metric_fl:: pdf_fcn_0_bit must be " - "a non-null pointer to function.\n"); - assert (0); - } - if (! pdf_fcn_1_bit) { - fprintf (stderr, "code_metric_fl:: pdf_fcn_0_bit must be " - "a non-null pointer to function.\n"); - assert (0); - } - if (sample_precision < 16 || sample_precision > 32) { - fprintf (stderr, "code_metric_fl:: sample_precision must be " - "between 16 and 32 for this class.\n"); - assert (0); - } + // internally, all samples are taken as pdf_fcn_io_t initially, and + // only converted to other values by their specific constructors. - d_sample_precision = sample_precision; d_n_samples = n_samples; d_max_sample = max_sample; d_min_sample = min_sample; - d_delta = (max_sample - min_sample) / (n_samples - 1); + 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; - d_metric_table_0_bit.assign (n_samples, 0); - d_metric_table_1_bit.assign (n_samples, 0); - - // get the scale factor for converting from float to sample_precision - // maps: - // logf (pdf_fcn_0_bit->eval (d_min_sample)) -> l_min_map - // logf (pdf_fcn_0_bit->eval (d_max_sample)) -> l_max_map - - metric_t l_min_map = - (1 << (sample_precision - 1)); - pdf_fcn_io_t l_min_log_val_0 = logf ((*pdf_fcn_0_bit)(d_min_sample)); - pdf_fcn_io_t l_max_log_val_0 = logf ((*pdf_fcn_0_bit)(d_max_sample)); - pdf_fcn_io_t l_slope_0 = (powf (2.0, (pdf_fcn_io_t)(d_sample_precision)) / - (l_max_log_val_0 - l_min_log_val_0)); - pdf_fcn_io_t l_min_log_val_1 = logf ((*pdf_fcn_1_bit)(d_min_sample)); - pdf_fcn_io_t l_max_log_val_1 = logf ((*pdf_fcn_1_bit)(d_max_sample)); - pdf_fcn_io_t l_slope_1 = (powf (2.0, (pdf_fcn_io_t)(d_sample_precision)) / - (l_max_log_val_1 - l_min_log_val_1)); + // 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 l_val = d_min_sample; - for (size_t m = 0; m < d_n_samples; m++) { - d_metric_table_0_bit[m] = - (metric_t) roundf (((pdf_fcn_io_t) l_min_map) + - (l_slope_0 * (logf ((*pdf_fcn_0_bit)(l_val)) - - l_min_log_val_0))); - d_metric_table_1_bit[m] = - (metric_t) roundf (((pdf_fcn_io_t) l_min_map) + - (l_slope_1 * (logf ((*pdf_fcn_1_bit)(l_val)) - - l_min_log_val_1))); - l_val += d_delta; + 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; -void code_metric_fl::lookup -(pdf_fcn_io_t sym, - void* bit_0, - void* bit_1) -{ - metric_ptr_t l_bit_0 = (metric_ptr_t) bit_0; - metric_ptr_t l_bit_1 = (metric_ptr_t) bit_1; + // take the logf so that metrics can add - if (sym <= d_min_sample) { - *l_bit_0 = d_metric_table_0_bit[0]; - *l_bit_1 = d_metric_table_1_bit[0]; - return; + 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]); } - if (sym >= d_max_sample) { - *l_bit_0 = d_metric_table_0_bit.back (); - *l_bit_1 = d_metric_table_1_bit.back (); - return; + 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)); } - size_t l_ndx = (size_t) roundf ((sym - d_min_sample) / d_delta); - *l_bit_0 = d_metric_table_0_bit[l_ndx]; - *l_bit_1 = d_metric_table_1_bit[l_ndx]; -} + // correct the delta to the lookup computations -void code_metric_fl::convert -(size_t n_syms, - pdf_fcn_io_t* sym, - void* bit_0, - void* bit_1) -{ - metric_ptr_t l_bit_0 = (metric_ptr_t) bit_0; - metric_ptr_t l_bit_1 = (metric_ptr_t) bit_1; - - for (size_t m = n_syms; m > 0; m--) - lookup (*sym++, (void*) l_bit_0++, (void*) l_bit_1++); + d_delta = (max_sample - min_sample) / ((pdf_fcn_io_t)(n_samples-1)); } -code_metric_fs::code_metric_fs +template +code_metrics_table_work::code_metrics_table_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_metrics_table + (pdf_fcn_0_bit, + pdf_fcn_1_bit, + n_samples, + min_sample, + max_sample) { - if (n_samples < 2) { - fprintf (stderr, "code_metric_fs:: n_samples " - "must be at least 2.\n"); - assert (0); - } - if (min_sample >= max_sample) { - fprintf (stderr, "code_metric_fs:: min_sample must be " - "less than max_sample.\n"); - assert (0); - } - if (! pdf_fcn_0_bit) { - fprintf (stderr, "code_metric_fs:: pdf_fcn_0_bit must be " - "a non-null pointer to function.\n"); - assert (0); - } - if (! pdf_fcn_1_bit) { - fprintf (stderr, "code_metric_fs:: pdf_fcn_0_bit must be " - "a non-null pointer to function.\n"); - assert (0); - } - if (sample_precision < 9 || sample_precision > 16) { - fprintf (stderr, "code_metric_fs:: sample_precision must be " - "between 9 and 16 for this class.\n"); - assert (0); - } + code_metrics_table::d_out_item_size_bytes = sizeof (metric_t); + code_metrics_table::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_sample_precision = sample_precision; - d_n_samples = n_samples; - d_max_sample = max_sample; - d_min_sample = min_sample; - d_delta = (max_sample - min_sample) / (n_samples - 1); - d_pdf_fcn_0_bit = pdf_fcn_0_bit; - d_pdf_fcn_1_bit = pdf_fcn_1_bit; d_metric_table_0_bit.assign (n_samples, 0); - d_metric_table_1_bit.assign (n_samples, 0); + for (size_t m = 0; m < n_samples; m++) { + d_metric_table_0_bit[m] = + (metric_t)((code_metrics_table::d_pdf_fcn_0_samples[m]) * + t_mult); + } - // get the scale factor for converting from float to sample_precision - // maps: - // logf (pdf_fcn_0_bit->eval (d_min_sample)) -> l_min_map - // logf (pdf_fcn_0_bit->eval (d_max_sample)) -> l_max_map + // clear the old float sample vectors to free memory - metric_t l_min_map = - (1 << (sample_precision - 1)); + code_metrics_table::d_pdf_fcn_0_samples.resize (0); - pdf_fcn_io_t l_min_log_val_0 = logf ((*pdf_fcn_0_bit)(d_min_sample)); - pdf_fcn_io_t l_max_log_val_0 = logf ((*pdf_fcn_0_bit)(d_max_sample)); - pdf_fcn_io_t l_slope_0 = (powf (2.0, (pdf_fcn_io_t)(d_sample_precision)) / - (l_max_log_val_0 - l_min_log_val_0)); - pdf_fcn_io_t l_min_log_val_1 = logf ((*pdf_fcn_1_bit)(d_min_sample)); - pdf_fcn_io_t l_max_log_val_1 = logf ((*pdf_fcn_1_bit)(d_max_sample)); - pdf_fcn_io_t l_slope_1 = (powf (2.0, (pdf_fcn_io_t)(d_sample_precision)) / - (l_max_log_val_1 - l_min_log_val_1)); + // convert the 1 bit metrics from float to integer - pdf_fcn_io_t l_val = d_min_sample; - for (size_t m = 0; m < d_n_samples; m++) { - d_metric_table_0_bit[m] = - (metric_t) roundf (((pdf_fcn_io_t) l_min_map) + - (l_slope_0 * (logf ((*pdf_fcn_0_bit)(l_val)) - - l_min_log_val_0))); + 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) roundf (((pdf_fcn_io_t) l_min_map) + - (l_slope_1 * (logf ((*pdf_fcn_1_bit)(l_val)) - - l_min_log_val_1))); - l_val += d_delta; + (metric_t)((code_metrics_table::d_pdf_fcn_1_samples[m]) * + t_mult); } + + // clear the old float sample vectors to free memory + + code_metrics_table::d_pdf_fcn_1_samples.resize (0); } -void code_metric_fs::lookup +template +void +code_metrics_table_work::lookup (pdf_fcn_io_t sym, void* bit_0, void* bit_1) @@ -304,23 +291,27 @@ void code_metric_fs::lookup metric_ptr_t l_bit_0 = (metric_ptr_t) bit_0; metric_ptr_t l_bit_1 = (metric_ptr_t) bit_1; - if (sym <= d_min_sample) { + if (sym <= code_metrics_table::d_min_sample) { *l_bit_0 = d_metric_table_0_bit[0]; *l_bit_1 = d_metric_table_1_bit[0]; return; } - if (sym >= d_max_sample) { + if (sym >= code_metrics_table::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) roundf ((sym - d_min_sample) / d_delta); + size_t l_ndx = (size_t) round + ((double)((sym - code_metrics_table::d_min_sample) / + code_metrics_table::d_delta)); *l_bit_0 = d_metric_table_0_bit[l_ndx]; *l_bit_1 = d_metric_table_1_bit[l_ndx]; } -void code_metric_fs::convert +template +void +code_metrics_table_work::convert (size_t n_syms, pdf_fcn_io_t* sym, void* bit_0, @@ -333,113 +324,88 @@ void code_metric_fs::convert lookup (*sym++, (void*) l_bit_0++, (void*) l_bit_1++); } -code_metric_fb::code_metric_fb -(pdf_fcn_t pdf_fcn_0_bit, - pdf_fcn_t pdf_fcn_1_bit, - size_t n_samples, - pdf_fcn_io_t min_sample, - pdf_fcn_io_t max_sample, - int sample_precision) -{ - if (n_samples < 2) { - fprintf (stderr, "code_metric_fb:: n_samples " - "must be at least 2.\n"); - assert (0); - } - if (min_sample >= max_sample) { - fprintf (stderr, "code_metric_fb:: min_sample must be " - "less than max_sample.\n"); - assert (0); - } - if (! pdf_fcn_0_bit) { - fprintf (stderr, "code_metric_fb:: pdf_fcn_0_bit must be " - "a non-null pointer to function.\n"); - assert (0); - } - if (! pdf_fcn_1_bit) { - fprintf (stderr, "code_metric_fb:: pdf_fcn_0_bit must be " - "a non-null pointer to function.\n"); - assert (0); - } - if (sample_precision < 1 || sample_precision > 8) { - fprintf (stderr, "code_metric_fb:: sample_precision must be " - "between 1 and 8 for this class.\n"); - assert (0); - } +#if 0 + // for compute_all_outputs - d_sample_precision = sample_precision; - d_n_samples = n_samples; - d_max_sample = max_sample; - d_min_sample = min_sample; - d_delta = (max_sample - min_sample) / (n_samples - 1); - d_pdf_fcn_0_bit = pdf_fcn_0_bit; - d_pdf_fcn_1_bit = pdf_fcn_1_bit; - d_metric_table_0_bit.assign (n_samples, 0); - d_metric_table_1_bit.assign (n_samples, 0); + d_n_code_outputs = n_code_outputs; - // get the scale factor for converting from float to sample_precision - // maps: - // logf (pdf_fcn_0_bit->eval (d_min_sample)) -> l_min_map - // logf (pdf_fcn_0_bit->eval (d_max_sample)) -> l_max_map + 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); - metric_t l_min_map = - (1 << (sample_precision - 1)); - pdf_fcn_io_t l_min_log_val_0 = logf ((*pdf_fcn_0_bit)(d_min_sample)); - pdf_fcn_io_t l_max_log_val_0 = logf ((*pdf_fcn_0_bit)(d_max_sample)); - pdf_fcn_io_t l_slope_0 = (powf (2.0, (pdf_fcn_io_t)(d_sample_precision)) / - (l_max_log_val_0 - l_min_log_val_0)); - pdf_fcn_io_t l_min_log_val_1 = logf ((*pdf_fcn_1_bit)(d_min_sample)); - pdf_fcn_io_t l_max_log_val_1 = logf ((*pdf_fcn_1_bit)(d_max_sample)); - pdf_fcn_io_t l_slope_1 = (powf (2.0, (pdf_fcn_io_t)(d_sample_precision)) / - (l_max_log_val_1 - l_min_log_val_1)); - pdf_fcn_io_t l_val = d_min_sample; - for (size_t m = 0; m < d_n_samples; m++) { - d_metric_table_0_bit[m] = - (metric_t) roundf (((pdf_fcn_io_t) l_min_map) + - (l_slope_0 * (logf ((*pdf_fcn_0_bit)(l_val)) - - l_min_log_val_0))); - d_metric_table_1_bit[m] = - (metric_t) roundf (((pdf_fcn_io_t) l_min_map) + - (l_slope_1 * (logf ((*pdf_fcn_1_bit)(l_val)) - - l_min_log_val_1))); - l_val += d_delta; + if (n_code_outputs == 0) { + std::cerr << "code_metrics::create: Error: # of code outputs " + "must be positive.\n"; + assert (0); } -} -void code_metric_fb::lookup -(pdf_fcn_io_t sym, - void* bit_0, - void* bit_1) -{ - metric_ptr_t l_bit_0 = (metric_ptr_t) bit_0; - metric_ptr_t l_bit_1 = (metric_ptr_t) bit_1; - if (sym <= d_min_sample) { - *l_bit_0 = d_metric_table_0_bit[0]; - *l_bit_1 = d_metric_table_1_bit[0]; - return; - } - if (sym >= d_max_sample) { - *l_bit_0 = d_metric_table_0_bit.back (); - *l_bit_1 = d_metric_table_1_bit.back (); - return; +template +void +code_metrics::compute_all_outputs +(pdf_fcn_io_t* syms, + std::vector& out) +{ + // use the first 'n_code_output' symbols, convert them into metrics, + // then compute all possible (summation) combinations of them and + // return those in the provided vector. + + convert (d_n_code_outputs, syms, + (void*)(&(in_l[0][0])), (void*)(&in_l[1][0])); + + // assign the starting minimum metric to 0. This is safe because + // metrics are always non-negative. + + unsigned long min_metric = 0; + for (size_t m = 0; m < (((size_t)2) << d_n_code_outputs); m++) { + size_t t_out_ndx = m; + unsigned long t_metric = 0; + for (size_t n = 0; n < d_n_code_outputs; n++, t_out_ndx >>= 1) + t_metric += in_l[t_out_ndx&1][n]; + if (t_metric < min_metric) + min_metric = t_metric; + out[m] = t_metric; } - size_t l_ndx = (size_t) roundf ((sym - d_min_sample) / d_delta); - *l_bit_0 = d_metric_table_0_bit[l_ndx]; - *l_bit_1 = d_metric_table_1_bit[l_ndx]; + // normalize so that the minimum metric equals 0 + + for (size_t m = 0; m < d_n_code_outputs; m++) + out[m] -= min_metric; } -void code_metric_fb::convert -(size_t n_syms, - pdf_fcn_io_t* sym, - void* bit_0, - void* bit_1) +template +void +code_metrics::compute_all_outputs +(pdf_fcn_io_t* syms, + std::vector& out) { - metric_ptr_t l_bit_0 = (metric_ptr_t) bit_0; - metric_ptr_t l_bit_1 = (metric_ptr_t) bit_1; + // use the first 'n_code_output' symbols, convert them into metrics, + // then compute all possible (summation) combinations of them and + // return those in the provided vector. + + convert (d_n_code_outputs, syms, + (void*)(&(in_f[0][0])), (void*)(&in_f[1][0])); + + // assign the starting minimum metric to 0. This is safe because + // metrics are always non-negative. + + float min_metric = 0; + for (size_t m = 0; m < (((size_t)2) << d_n_code_outputs); m++) { + size_t t_out_ndx = m; + float t_metric = 0; + for (size_t n = 0; n < d_n_code_outputs; n++, t_out_ndx >>= 1) + t_metric += in_f[t_out_ndx&1][n]; + if (t_metric < min_metric) + min_metric = t_metric; + out[m] = t_metric; + } - for (size_t m = n_syms; m > 0; m--) - lookup (*sym++, (void*) l_bit_0++, (void*) l_bit_1++); + // normalize so that the minimum metric equals 0 + + for (size_t m = 0; m < d_n_code_outputs; m++) + out[m] -= min_metric; } +#endif diff --git a/gr-error-correcting-codes/src/lib/libecc/code_metrics.h b/gr-error-correcting-codes/src/lib/libecc/code_metrics.h index 9530dd640..050c08192 100644 --- a/gr-error-correcting-codes/src/lib/libecc/code_metrics.h +++ b/gr-error-correcting-codes/src/lib/libecc/code_metrics.h @@ -20,136 +20,153 @@ * Boston, MA 02111-1307, USA. */ -#ifndef INCLUDED_CODE_METRIC_H -#define INCLUDED_CODE_METRIC_H +#ifndef INCLUDED_CODE_METRICS_H +#define INCLUDED_CODE_METRICS_H -#include +#include "code_types.h" #include -class code_metrics +template +class code_metrics_table; + +template +code_metrics_table* +libecc_code_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 = 0); + +#if 0 +template +class code_metrics_decoder; + +template +libecc_code_metrics_create_decoder +(code_convolutional_trellis* trellis, + code_metrics_table* table = 0, + int sample_precision = 0); +#endif + +template +class code_metrics_table { +/* + * class code_metrics_table: 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 float pdf_fcn_io_t; + typedef pdf_fcn_io_t (*pdf_fcn_t) (pdf_fcn_io_t); - code_metrics () {}; - virtual ~code_metrics () {}; + virtual ~code_metrics_table () {}; -// lookup() returns either a float, or a sign-extended -// 'sample_precision'-bit integer value. + // 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; -}; -class code_metric_ff : public code_metrics -{ - typedef pdf_fcn_io_t (*pdf_fcn_t) (pdf_fcn_io_t); - typedef float metric_t, *metric_ptr_t; + inline const unsigned char out_item_size_bytes () + {return(d_out_item_size_bytes);}; -private: +protected: + code_metrics_table (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 d_metric_table_0_bit; - std::vector d_metric_table_1_bit; - -public: - code_metric_ff (pdf_fcn_t pdf_fcn_0_bit, - pdf_fcn_t pdf_fcn_1_bit, - size_t n_samples, - pdf_fcn_io_t min_sample, - pdf_fcn_io_t max_sample); - ~code_metric_ff () {}; - - 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); + std::vector d_pdf_fcn_0_samples, d_pdf_fcn_1_samples; }; -class code_metric_fl : public code_metrics +template +class code_metrics_table_work : public code_metrics_table { - typedef float pdf_fcn_io_t; - typedef pdf_fcn_io_t (*pdf_fcn_t) (pdf_fcn_io_t); - typedef long metric_t, *metric_ptr_t; - -private: - char d_sample_precision; - size_t d_n_samples, d_sample_mask; - 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 d_metric_table_0_bit; - std::vector d_metric_table_1_bit; - public: - code_metric_fl (pdf_fcn_t pdf_fcn_0_bit, - pdf_fcn_t pdf_fcn_1_bit, - size_t n_samples, - pdf_fcn_io_t min_sample, - pdf_fcn_io_t max_sample, - int sample_precision = 32); - ~code_metric_fl () {}; - - 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); -}; - -class code_metric_fs : public code_metrics -{ - typedef float pdf_fcn_io_t; + typedef metric_t *metric_ptr_t; typedef pdf_fcn_io_t (*pdf_fcn_t) (pdf_fcn_io_t); - typedef short metric_t, *metric_ptr_t; -private: - char d_sample_precision; - size_t d_n_samples, d_sample_mask; - 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 d_metric_table_0_bit; - std::vector d_metric_table_1_bit; - -public: - code_metric_fs (pdf_fcn_t pdf_fcn_0_bit, - pdf_fcn_t pdf_fcn_1_bit, - size_t n_samples, - pdf_fcn_io_t min_sample, - pdf_fcn_io_t max_sample, - int sample_precision = 16); - ~code_metric_fs () {}; + ~code_metrics_table_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); -}; -class code_metric_fb : public code_metrics -{ - typedef float pdf_fcn_io_t; - typedef pdf_fcn_io_t (*pdf_fcn_t) (pdf_fcn_io_t); - typedef char metric_t, *metric_ptr_t; +protected: + code_metrics_table_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 = 0); + + friend code_metrics_table* + libecc_code_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); + + std::vector d_metric_table_0_bit, d_metric_table_1_bit; +}; -private: - char d_sample_precision; - size_t d_n_samples, d_sample_mask; - 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 d_metric_table_0_bit; - std::vector d_metric_table_1_bit; +#if 0 + // compute all output-bit combinations of the incoming symbols' metrics -public: - code_metric_fb (pdf_fcn_t pdf_fcn_0_bit, - pdf_fcn_t pdf_fcn_1_bit, - size_t n_samples, - pdf_fcn_io_t min_sample, - pdf_fcn_io_t max_sample, - int sample_precision = 8); - ~code_metric_fb () {}; + void compute_all_outputs (pdf_fcn_io_t* syms, std::vector& out); + void compute_all_outputs (pdf_fcn_io_t* syms, std::vector& out); - 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); -}; + size_t d_n_code_outputs; + std::vector in_l[2]; + std::vector in_f[2]; +#endif -#endif /* INCLUDED_CODE_METRIC_H */ +#endif /* INCLUDED_CODE_METRICS_H */ diff --git a/gr-error-correcting-codes/src/lib/libecc/decoder.cc b/gr-error-correcting-codes/src/lib/libecc/decoder.cc index 0b77f779e..256880e13 100644 --- a/gr-error-correcting-codes/src/lib/libecc/decoder.cc +++ b/gr-error-correcting-codes/src/lib/libecc/decoder.cc @@ -25,93 +25,180 @@ #endif #include -#include #include -#define DO_PRINT_DEBUG 1 - -#if DO_PRINT_DEBUG -#include -#endif +#define DO_PRINT_DEBUG 0 /* * decode a certain number of output bits * * the 'in_buf' and 'out_buf' must have enough memory to handle the - * number of input metrics and output bits; no error checking is done! + * number of input items and output bits; no error checking is done! * - * n_bits_to_output: the number of bits per output stream to output. + * n_bits_to_output: the number of bits per output stream to decode. * - * returns the actual number of metrics used per input stream. + * returns the actual number of items used per input stream. */ size_t decoder::decode -(const char** in_buf, - char** out_buf, +(const code_input_ptr in_buf, + code_output_ptr out_buf, size_t n_bits_to_output) { + if (in_buf == 0) { + std::cerr << "decoder::decode: Error: input buffer is NULL.\n"; + assert (0); + } + if (out_buf == 0) { + std::cerr << "decoder::decode: Error: output buffer is NULL.\n"; + assert (0); + } + if (n_bits_to_output == 0) { + std::cerr << "decoder::decode: Warning: no output bits requested.\n"; + return (0); + } + // set the class-internal number of input metrics // and output bits left to decode - size_t saved_n_input_metrics; - saved_n_input_metrics = d_n_input_metrics_left = - compute_n_input_metrics (n_bits_to_output); - d_n_output_bits_left = n_bits_to_output; + d_in_buf = in_buf; + d_out_buf = out_buf; + + // check that there are enough output buffer items + + if (d_out_buf->n_items_left() < n_bits_to_output) { + std::cerr << "encoder::encode: Warning: output buffer size (" << + d_out_buf->n_items_left() << "is less than the desired number " + "of output items (" << n_bits_to_output << + ") ... using lower number.\n"; + n_bits_to_output = d_out_buf->n_items_left(); + } + + // check that there are enough input buffer items + + size_t n_items_to_input = compute_n_input_items (n_bits_to_output); + + if (d_in_buf->n_items_left() < n_items_to_input) { + std::cerr << "encoder::encode: Warning: input buffer size (" << + d_in_buf->n_items_left() << "is less than the computed number " + "of required input items (" << n_items_to_input << + ") ... using lower number.\n"; + n_items_to_input = d_in_buf->n_items_left(); + n_bits_to_output = compute_n_output_bits (n_items_to_input); + } + + if (DO_PRINT_DEBUG) { + std::cout << + "# output bits = " << n_bits_to_output << "\n" + "# input items = " << n_items_to_input << "\n"; + } // call the private decode function - decode_private (in_buf, out_buf); + decode_private (); if (DO_PRINT_DEBUG) { - std::cout << "n_input_metrics_used = " << - (saved_n_input_metrics - d_n_input_metrics_left) << "\n" - "n_output_bits_used = " << - (n_bits_to_output - d_n_output_bits_left) << '\n'; + std::cout << + "# input items used = " << d_in_buf->n_items_used() << "\n" + "# output bits used = " << d_out_buf->n_items_used() << "\n"; } - // return the actual number of input metrics used + size_t n_items_used = d_in_buf->n_items_used (); + + // clear these buffers, just in case + + d_in_buf = 0; + d_out_buf = 0; - return (saved_n_input_metrics - d_n_input_metrics_left); + // return the actual number of input bits used + + return (n_items_used); } /* * decode a certain number of input metrics * * the 'in_buf' and 'out_buf' must have enough memory to handle the - * number of input metrics and output bits; no error checking is done! + * number of input items and output bits; no error checking is done! * - * n_metrics_to_input: the number of metrics per input stream to decode + * n_items_to_input: the number of items per input stream to decode * * returns the actual number of bits written per output stream */ size_t decoder::decode -(const char** in_buf, - size_t n_metrics_to_input, - char** out_buf) +(const code_input_ptr in_buf, + size_t n_items_to_input, + code_output_ptr out_buf) { + if (in_buf == 0) { + std::cerr << "encoder::encode: Error: input buffer is NULL.\n"; + assert (0); + } + if (out_buf == 0) { + std::cerr << "encoder::encode: Error: output buffer is NULL.\n"; + assert (0); + } + if (n_items_to_input == 0) { + std::cerr << "encoder::encode: Warning: no input items requested.\n"; + return (0); + } + // set the class-internal number of input metrics and // output bits left to decode - size_t saved_n_output_bits; - saved_n_output_bits = d_n_output_bits_left = - compute_n_output_bits (n_metrics_to_input); - d_n_input_metrics_left = n_metrics_to_input; + d_in_buf = in_buf; + d_out_buf = out_buf; + + // check that there are enough input buffer items + + if (d_in_buf->n_items_left() < n_items_to_input) { + std::cerr << "encoder::encode: Warning: input buffer size (" << + d_in_buf->n_items_left() << "is less than the desired number " + "of input items (" << n_items_to_input << + ") ... using lower number.\n"; + n_items_to_input = d_in_buf->n_items_left(); + } + + // check that there are enough output buffer items + + size_t n_bits_to_output = compute_n_output_bits (n_items_to_input); + + if (d_out_buf->n_items_left() < n_bits_to_output) { + std::cerr << "encoder::encode: Warning: output buffer size (" << + d_out_buf->n_items_left() << "is less than the computed number " + "of required output items (" << n_bits_to_output << + ") ... using lower number.\n"; + n_bits_to_output = d_out_buf->n_items_left(); + n_items_to_input = compute_n_input_items (n_bits_to_output); + } + + if (DO_PRINT_DEBUG) { + std::cout << + "# output bits = " << n_bits_to_output << "\n" + "# input items = " << n_items_to_input << "\n"; + } // call the private decode function - decode_private (in_buf, out_buf); + decode_private (); if (DO_PRINT_DEBUG) { - std::cout << "n_input_metrics_used = " << - (n_metrics_to_input - d_n_input_metrics_left) << '\n'; - std::cout << "n_output_bits_used = " << - (saved_n_output_bits - d_n_output_bits_left) << '\n'; + std::cout << + "# input items used = " << d_in_buf->n_items_used() << "\n" + "# output bits used = " << d_out_buf->n_items_used() << "\n"; } + size_t n_items_used = d_out_buf->n_items_used(); + + // clear these buffers, just in case + + d_in_buf = 0; + d_out_buf = 0; + // return the actual number of output bits written - return (saved_n_output_bits - d_n_output_bits_left); + return (n_items_used); } diff --git a/gr-error-correcting-codes/src/lib/libecc/decoder.h b/gr-error-correcting-codes/src/lib/libecc/decoder.h index 76a24b20a..860800110 100644 --- a/gr-error-correcting-codes/src/lib/libecc/decoder.h +++ b/gr-error-correcting-codes/src/lib/libecc/decoder.h @@ -23,37 +23,69 @@ #ifndef INCLUDED_DECODER_H #define INCLUDED_DECODER_H -#include "code_types.h" - -// the 'decoder' class is a virtual class upon which all decoder types -// can be built. +#include "code_io.h" class decoder { + /* + * class decoder + * A virtual class upon which all decoder types can be built. + * This class provides the basic methods and variables + * generic for all decoders. + */ public: decoder () {}; virtual ~decoder () {}; - virtual size_t compute_n_input_metrics (size_t n_output_bits) = 0; - virtual size_t compute_n_output_bits (size_t n_input_metrics) = 0; - virtual size_t decode (const char** in_buf, - char** out_buf, + /* + * compute_n_...: to be defined by inheriting classes, in order to + * allow for user-functions to figure out how many inputs are + * required to generate a given number of outputs, and vice versa. + * Can't define them without knowing the decoder type. + * + * Compute the number of input items (metrics, floats, whatevers) + * needed to produce 'n_output' bits, and the number of output bits + * which will be produced by 'n_input' items ... for a single stream + * only. + */ + + virtual size_t compute_n_input_items (size_t n_output_bits) = 0; + virtual size_t compute_n_output_bits (size_t n_input_items) = 0; + + /* + * decode: given the input and output buffers, either decode up to + * the number of output bits or decode the number of input items + * ... if the buffers support either decoding amounts. + */ + + virtual size_t decode (const code_input_ptr in_buf, + code_output_ptr out_buf, size_t n_bits_to_output); - virtual size_t decode (const char** in_buf, - size_t n_metrics_to_input, - char** out_buf); + virtual size_t decode (const code_input_ptr in_buf, + size_t n_items_to_input, + code_output_ptr out_buf); + +/* for remote access to internal info */ + + inline const size_t block_size_bits () {return (d_block_size_bits);}; + inline const size_t n_code_inputs () {return (d_n_code_inputs);}; + inline const size_t n_code_outputs () {return (d_n_code_outputs);}; + inline const size_t total_n_dec_bits () {return (d_total_n_dec_bits);}; protected: - virtual void decode_private (const char** in_buf, char** out_buf) = 0; - virtual char get_next_input (const char** in_buf, size_t code_input_n) = 0; - virtual void output_bit (char t_out_bit, char** out_buf, - size_t t_output_stream) = 0; + /* + * decode_private: decode the given in_buf and write the output bits + * to the out_buf, using internal class variables. This function is + * called from the publically available "encode()" methods, which + * first set the internal class variables before executing. + */ + + virtual void decode_private () = 0; size_t d_block_size_bits, d_n_code_inputs, d_n_code_outputs; - size_t d_n_dec_bits; - size_t d_in_buf_ndx, d_out_buf_ndx; - size_t d_in_bit_shift, d_out_bit_shift; - size_t d_n_input_metrics_left, d_n_output_bits_left; + size_t d_total_n_dec_bits; + code_input_ptr d_in_buf; + code_output_ptr d_out_buf; }; #endif /* INCLUDED_DECODER_H */ diff --git a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.cc b/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.cc index bce2cacb2..7e50d8936 100644 --- a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.cc +++ b/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.cc @@ -52,55 +52,45 @@ const int g_num_bits_per_byte = 8; #define DO_PRINT_DEBUG_EXIT 0 #define DO_PRINT_DEBUG 0 -#if DO_TIME_THOUGHPUT #include -#endif -#if DO_PRINT_DEBUG #include -#endif decoder_viterbi::decoder_viterbi (int sample_precision, - encoder_convolutional* l_encoder) + const encoder_convolutional* l_encoder) { - // make sure the sample precitions makes sense + // make sure that the encoder is "valid" - if ((sample_precision < 0) | (sample_precision > 32)) { - std::cerr << "decoder_viterbi: " - "Requested sample_precision (" << sample_precision << - "must be between 0 and 32.\n"; + if (! l_encoder) { + std::cerr << "decoder_viterbi: Error: Encoder is NULL.\n"; assert (0); } - // make sure that the encoder is "valid" + // make the metrics converter - if (! l_encoder) { - std::cerr << "decoder_viterbi: Error: Encoder is a NULL pointer.\n"; + // 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"; assert (0); } - // keep around a pointer to the encoder + // get the trellis - d_encoder = l_encoder; + d_encoder = (encoder_convolutional*) l_encoder; + d_trellis = (code_convolutional_trellis*) d_encoder->trellis (); // fill the class variables d_block_size_bits = d_encoder->block_size_bits (); - d_do_streaming = (d_block_size_bits == 0); 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 (); -#if 0 - d_total_memory = d_encoder->total_memory (); -#endif - - // NOTE: d_n_states is a 'long', and thus is quite limited in terms - // of max memory and # of input streams to 2^32 states This is OK, - // since that many states would be impossibly slow to decode! might - // make this a "long long" (64 bits) in the future - - d_n_states = 1 << d_total_memory; - d_n_input_combinations = 1 << d_n_code_inputs; + d_total_n_delays = d_encoder->total_n_delays (); + d_n_states = d_trellis->n_states (); + d_n_input_combinations = d_trellis->n_input_combinations (); // really nothing else to do here, since this class doesn't "know" // how to process streaming versus block decoding, or partial @@ -112,11 +102,9 @@ decoder_viterbi::decoder_viterbi "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_streaming = " << - ((d_do_streaming == true) ? "true" : "false") << "\n" << "d_do_termination = " << ((d_do_termination == true) ? "true" : "false") << "\n" << - "d_total_memory = " << d_total_memory << "\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"; } @@ -134,17 +122,14 @@ decoder_viterbi::decoder_viterbi d_n_total_inputs_per_stream = d_block_size_bits; if (d_do_termination == true) - d_n_total_inputs_per_stream += d_max_memory; - - - + d_n_total_inputs_per_stream += d_total_n_delays; } decoder_viterbi::~decoder_viterbi () { // reverse over from allocation - +#if 0 delete [] d_up_term_states_ndx[0]; delete [] d_up_term_states_ndx[1]; @@ -177,6 +162,7 @@ decoder_viterbi::~decoder_viterbi delete [] (*t_save_buffer++); } delete [] d_save_buffer; +#endif } void @@ -209,20 +195,9 @@ decoder_viterbi::zero_metrics } } -//FIXME - -char -decoder_viterbi::get_next_input -(const char** in_buf, -size_t code_input_n) -{ - return (0); -} - void decoder_viterbi::decode_private -(const char** in_buf, - char** out_buf) +() { #if 0 @@ -231,8 +206,8 @@ decoder_viterbi::decode_private start_timer (&t_tp); #endif #if DO_PRINT_DEBUG - size_t t_state_print_bits = d_total_memory + 1; - size_t t_mem_print_bits = d_max_memory + 2; + 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]; @@ -319,148 +294,8 @@ decoder_viterbi::decode_private // jump to the correct state in the fsm switch (d_fsm_state) { case fsm_dec_viterbi_doing_up: -#if DO_PRINT_DEBUG_FSM - std::cout << "Starting fsm_dec_viterbi_doing_up\n"; -#endif -// set the number of up_down indices - size_t t_n_up_down_ndx = 1 << (d_n_code_inputs * - d_time_count); -// stay in this state until the correct number of input symbols are -// reached; exit also if we run out of input symbols to process - while ((d_time_count < d_max_memory) & - (t_in_buf_ndx < t_ninput_items)) { -#if DO_PRINT_DEBUG_UP_0 - std::cout << "Doing 'while' loop:\n" << - "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" << - "d_time_count = " << d_time_count << "\n" << - "d_max_memory = " << d_max_memory << "\n" << - "t_in_buf_ndx = " << t_in_buf_ndx << "\n" << - "t_ninput_items = " << t_ninput_items << "\n"; -#endif -// use the "from" states, loop over all inputs and compute the metric for -// each & store it in the "to" state at the end of the connection. -// no need to compare metrics yet, since none join into any given state - #if 0 -// reset the "to" state's metrics -// probably don't need to do this; try removing later - reset_metrics (d_states_ndx ^ 1); -#if DO_PRINT_DEBUG_UP - std::cout << "Reset Metrics\n"; -#endif -#endif - -// reset the state's index for each set of new inputs - size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx]; - size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1]; -// loop over all current stored "up" states - for (size_t n = 0; n < t_n_up_down_ndx; n++) { - size_t t_state_ndx = *t_state_ndx_ptr++; -// get a pointer to this state's structure - state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]); -// get the connections for all inputs - connection_t_ptr t_connection = t_state->d_connections; -#if DO_PRINT_DEBUG_UP_0 - std::cout << "Looping over all 'up' states:\n" << - "n = " << n << "\n" << - "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" << - "d_states_ndx = " << d_states_ndx << "\n" << - "t_state_ndx = " << t_state_ndx << "\n" << - "d_n_input_combs = " << d_n_input_combinations << "\n" << - "t_state = " << t_state << "\n" << - "t_connection = " << t_connection << "\n"; -#endif -// loop over all possible input values, 1 bit per input stream - for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) { -// find the "to" state for this connection - state_t_ptr t_to_state = t_connection->d_to; -// get the output bits for this connection - float* t_output_bit = t_connection->d_output_bits; -// start with this state's metric - float t_metric = t_state->d_max_metric; -#if DO_PRINT_DEBUG_UP_0 - std::cout << - "to state index = " << t_connection->d_to_ndx << "\n" << - "current metric = " << t_metric << "\n"; -#endif - if (d_do_mux_inputs == true) { -// if using mux'ed input streams, handle differently - const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]); -// loop over all encoder-output values - for (size_t r = d_n_code_outputs; r > 0; r--) { -#if DO_PRINT_DEBUG_UP - std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " << - *t_output_bit << " ==> metric -> "; -#endif - t_metric += ((*t_in_buf++) * (*t_output_bit++)); -#if DO_PRINT_DEBUG_UP - std::cout << t_metric << "\n"; -#endif - } - } else { -// loop over all encoder-output values - for (size_t r = 0; r < d_n_code_outputs; r++) { -#if DO_PRINT_DEBUG_UP - std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] << - ", code_out_bit = " << *t_output_bit << " ==> metric -> "; -#endif - t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++)); -#if DO_PRINT_DEBUG_UP - std::cout << t_metric << "\n"; -#endif - } - } -// get the "to" state index - size_t t_to_ndx = t_connection->d_to_ndx; -// store the metric in the "to" state; should not have been used before - t_to_state->d_max_metric = t_metric; -// add the "to" state index to the "up" state list - *t_next_state_ndx_ptr++ = t_to_ndx; -// update the traceback structure, depending on which variety it is -// doing full trellis before decoding; use d_out_buf -// simple: get the current state & output state - traceback_t_ptr t_out_buf = &(d_out_buf[d_time_count] - [t_state_ndx]); - traceback_t_ptr t_next_out_buf = &(d_out_buf[d_time_count+1] - [t_to_ndx]); -#if DO_PRINT_DEBUG_UP_1 - std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n" << - "ndx[" << n << "] == " << t_state_ndx << - ", s[" << n2bs(t_state_ndx,t_state_print_bits) << - "]: max_ndx = " << - n2bs(t_state->d_max_state_ndx,t_state_print_bits) << - ", input = " << n2bs(q, d_n_code_inputs+1) << - ": " << t_next_out_buf << " => " << t_out_buf << "\n"; -#endif -// and connect output to the current, set inputs on output - t_next_out_buf->d_prev = t_out_buf; - t_next_out_buf->d_inputs = q; -// finished (for) this input value - } -// finished (for) this "up_term" state - } -// increment the in_buf index, depending on mux'ing or not - t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs; -// increment the time counter - d_time_count++; -// update the number of "up_term" states - d_up_term_ndx ^= 1; -// increase the number of using states - t_n_up_down_ndx <<= d_n_code_inputs; -// change which d_states' index to use as starting - d_states_ndx ^= 1; -// finished (while) staying in this fsm state or not - } -// if reached the end of doing the "up" part of the trellis, -// switch states into the middle - if (d_time_count == d_max_memory) { -#if DO_PRINT_DEBUG_FSM - std::cout << "Setting FSM to fsm_dec_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"; + encode_loop_up (); #endif break; case (fsm_dec_viterbi_doing_middle): @@ -486,7 +321,7 @@ decoder_viterbi::decode_private #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";; + "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++) { @@ -621,15 +456,15 @@ decoder_viterbi::decode_private 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_max_memory - (d_time_count - d_block_size_bits); + 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_max_memory - t_time_count + 1) << - " of " << d_max_memory << "; starting buf[" << t_in_buf_ndx << + 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, @@ -800,15 +635,15 @@ decoder_viterbi::decode_private // FIXME: assume termination state == 0 #if DO_PRINT_DEBUG_OUTPUT_0 std::cout << "Using termination; going through trellis for " << - d_max_memory << " bit" << - ((d_max_memory != 1) ? "s" : "") << "\n"; + 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_max_memory; n > 0; n--) { + 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"; @@ -1058,3 +893,157 @@ decoder_viterbi::decode_private " b/s\n"; #endif } + +#if 0 + +void +decoder_viterbi::encode_loop_up () +{ +#if DO_PRINT_DEBUG_FSM + std::cout << "Starting fsm_dec_viterbi_doing_up\n"; +#endif + + // set the number of up_down indices + + size_t t_n_up_down_ndx = 1 << (d_n_code_inputs * + d_time_count); + +// stay in this state until the correct number of input symbols are +// reached; exit also if we run out of input symbols to process + while ((d_time_count < d_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 diff --git a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.h b/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.h index 66a6ba405..e97f5cd10 100644 --- a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.h +++ b/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi.h @@ -48,31 +48,11 @@ public: */ decoder_viterbi (int sample_precision, - encoder_convolutional* l_encoder); + const encoder_convolutional* l_encoder); virtual ~decoder_viterbi (); protected: - struct state_t; - -/* - * connection_t: describes an output connection from the current - * time-bit memory state to the next time-bit memory state - * - * d_to: state pointer to which this connection going - * - * d_to_ndx: index of the "to" state - * - * d_output_bits: what are the output bits, coverted into - * 1->+1.0, 0->-1.0, for this connection - */ - - typedef struct connection_t { - struct state_t *d_to; - int d_to_ndx; - float* d_output_bits; - } connection_t, *connection_t_ptr; - /* * state_t: describes a given memory state * @@ -94,7 +74,7 @@ protected: */ typedef struct state_t { - connection_t_ptr d_connections; + struct state_t* d_connections; float d_max_metric; int d_max_state_ndx; int d_max_input; @@ -149,20 +129,21 @@ protected: fsm_dec_viterbi_doing_middle, fsm_dec_viterbi_doing_term }; - virtual void decode_private (const char** in_buf, char** out_buf); - virtual char get_next_input (const char** in_buf, size_t code_input_n); + virtual void decode_private (); #if 0 - virtual void decode_loop (const char** in_buf, char** out_buf, - size_t* which_counter, size_t how_many); - - virtual char get_next_input__up (const char** in_buf, - size_t code_input_n) = 0; - virtual char get_next_input__middle (const char** in_buf, - size_t code_input_n) = 0; - virtual char get_next_input__term (size_t code_input_n) = 0; + virtual void decode_loop (size_t* which_counter, size_t how_many); #endif - virtual void increment_input_indices (bool while_decoding) = 0; - virtual void increment_output_indices (bool while_decoding) = 0; + virtual void get_next_inputs () { + d_in_buf->read_items ((void*)(&(d_current_inputs[0]))); + d_in_buf->increment_indices (); + }; + 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; @@ -173,17 +154,32 @@ protected: 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_max_memory, d_total_memory; + size_t d_time_count, d_n_total_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; + 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_streaming, d_do_termination; - std::vector d_init_states, d_term_states; - char **d_save_buffer; + bool d_do_termination; +#if 1 state_t_ptr d_states[2]; size_t* d_up_term_states_ndx[2]; + char **d_save_buffer; +#else + std::vector d_states[2]; + std::vector d_up_term_states_ndx[2]; + std::vector d_save_buffer; ??? +#endif + + // "inputs" are the current input symbols as soft-floats, to be + // converted to metrics internally + + std::vector d_current_inputs; + + // "outputs" are the current output bits, in the LSB (&1) of each "char" + + std::vector d_current_outputs; }; #endif /* INCLUDED_DECODER_VITERBI_H */ diff --git a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.cc b/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.cc index 308d2775b..e604e4477 100644 --- a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.cc +++ b/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.cc @@ -127,6 +127,20 @@ decoder_viterbi_full_block::~decoder_viterbi_full_block delete [] d_out_buf; } +size_t +decoder_viterbi_full_block::compute_n_input_items +(size_t n_output_bits) +{ + return (0); +} + +size_t +decoder_viterbi_full_block::compute_n_output_bits +(size_t n_input_items) +{ + return (0); +} + void decoder_viterbi_full_block::update_traceback__up (size_t from_state_ndx, @@ -272,8 +286,7 @@ decoder_viterbi_full_block::update_traceback__term void decoder_viterbi_full_block::decode_private -(const char** in_buf, - char** out_buf) +() { #if 0 diff --git a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.h b/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.h index 531b7a6c6..832b656cc 100644 --- a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.h +++ b/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block.h @@ -29,8 +29,8 @@ class decoder_viterbi_full_block : public decoder_viterbi { /*! * \brief Decode the incoming streams using a Viterbi-style decoder, - * doing full trellis block decoding before putting out - * any bits + * doing full trellis block decoding before putting out any + * decoded bits. * * input: streams of metrics, two per code output: one for the 0-bit * metrics and the other for the 1-bit metric. @@ -44,8 +44,11 @@ public: virtual ~decoder_viterbi_full_block (); + virtual size_t compute_n_input_items (size_t n_output_bits); + virtual size_t compute_n_output_bits (size_t n_input_items); + protected: - virtual void decode_private (const char** in_buf, char** out_buf); + virtual void decode_private (); virtual void update_traceback__up (size_t from_state_ndx, size_t to_state_ndx, size_t l_input); diff --git a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block_i1_ic1.cc b/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block_i1_ic1.cc deleted file mode 100644 index b0fc4f364..000000000 --- a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block_i1_ic1.cc +++ /dev/null @@ -1,162 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "decoder_viterbi_full_block_i1_ic1.h" -#include -#include -#include - -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_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 1 - -#if DO_TIME_THOUGHPUT -#include -#endif -#if DO_PRINT_DEBUG -#include -#endif - -// FIXME - -size_t -decoder_viterbi_full_block_i1_ic1::compute_n_output_bits -(size_t n_input_items) -{ - assert (0); - return (0); -} - -/* - * Compute the number of input items (metrics) needed to produce - * 'noutput' bits. For convolutional decoders, there is 1 - * bit output per metric input per stream, with the addition of a some - * metrics for trellis termination if selected. Without termination, - * there is exactly 1:1 input to output (1 metric in to 1 bit out), - * no matter the encoding type. - * - * if (not terminating), then get the number of output bits. - * - * otherwise, find the number of blocks (not necessarily an integer), - * and then compute the number of input metrics (including termination) - * required to produce those blocks. Subtract the number of bits - * leftover from the previous computation, then find the number of input - * metrics, ceil'd to make sure there are enough. - */ - -size_t -decoder_viterbi_full_block_i1_ic1::compute_n_input_metrics -(size_t n_output_bits) -{ - int t_ninput_items = 0; - int t_noutput_bits = ((int) n_output_bits) - ((int) d_n_saved_bits); - - // if there are enough saved bits, just use those, no inputs required - - if (t_noutput_bits <= 0) - return (0); - - // remove any bits already in the decoding trellis - - if (d_time_count != 0) { - int t_time_bits = ((d_time_count > d_block_size_bits) ? 0 : - d_block_size_bits - d_time_count); - t_noutput_bits -= t_time_bits; - t_ninput_items += t_time_bits; - } - // if completing this trellis doesn't create enough outputs ... - - if (t_noutput_bits > 0) { - - // there is a 1:1 ratio between input symbols and output bits (per - // stream), except for termination bits which are already taken - // into account in the total # of input bits per stream class - // variable; need to round the # output bits to the - - // find the number of blocks, ceil'd to the next higher integer - - int t_nblocks = (int) ceilf (((float) t_noutput_bits) / - ((float) d_block_size_bits)); - - // find the number of required input bits - - t_ninput_items += t_nblocks * d_n_total_inputs_per_stream; - } - - return (t_ninput_items); -} - -// FIXME, from here down dummies to get correct compiling; for testing -// purposes only. - -void -decoder_viterbi_full_block_i1_ic1::increment_input_indices -(bool while_decoding) -{ - if (while_decoding) - std::cout << "foo!"; - -#if 0 -// 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; -#endif -} - -void -decoder_viterbi_full_block_i1_ic1::increment_output_indices -(bool while_decoding) -{ - if (while_decoding) - std::cout << "bar!"; -} - -void -decoder_viterbi_full_block_i1_ic1::output_bit -(char t_out_bit, - char** out_buf, - size_t t_output_stream) -{ - if (t_out_bit) - std::cout << "mop!"; -} diff --git a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block_i1_ic1.h b/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block_i1_ic1.h deleted file mode 100644 index a7afeb396..000000000 --- a/gr-error-correcting-codes/src/lib/libecc/decoder_viterbi_full_block_i1_ic1.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef INCLUDED_DECODER_VITERBI_FULL_BLOCK_IC1_H -#define INCLUDED_DECODER_VITERBI_FULL_BLOCK_IC1_H - -#include "decoder_viterbi_full_block.h" - -class decoder_viterbi_full_block_i1_ic1 : public decoder_viterbi_full_block -{ -/*! - * class decoder_viterbi_full_block_i1_ic1 : - * public decoder_viterbi_full_block - * - * Decode the incoming metrics using a Viterbi-style decoder, doing - * full trellis block decoding before putting out any bits - * - * input is "i1": one stream per input (as defined by the - * code-output), with one metric per input item. - * - * output is "ic1": streams of char, one stream per output (as defined - * by the code-input), using only the right-most justified (LSB?) - * bit as the single output bit per output item. - * - * The rest of the options are outlined in the inherited classes' - * header files. - */ - -public: - inline decoder_viterbi_full_block_i1_ic1 - (int sample_precision, - encoder_convolutional* l_encoder) - : decoder_viterbi_full_block (sample_precision, l_encoder) {}; - - virtual ~decoder_viterbi_full_block_i1_ic1 () {}; - - virtual size_t compute_n_input_metrics (size_t n_output_bits); - virtual size_t compute_n_output_bits (size_t n_input_metrics); - -protected: - virtual void increment_input_indices (bool while_decoding); - virtual void output_bit (char t_out_bit, char** out_buf, - size_t t_output_stream); - virtual void increment_output_indices (bool while_decoding); -}; - -#endif /* INCLUDED_DECODER_VITERBI_FULL_BLOCK_I1_IC1_H */ diff --git a/gr-error-correcting-codes/src/lib/libecc/encoder.cc b/gr-error-correcting-codes/src/lib/libecc/encoder.cc index 5bc97e7fc..967000fd0 100644 --- a/gr-error-correcting-codes/src/lib/libecc/encoder.cc +++ b/gr-error-correcting-codes/src/lib/libecc/encoder.cc @@ -42,43 +42,78 @@ size_t encoder::encode -(const char** in_buf, - char** out_buf, +(const code_input_ptr in_buf, + code_output_ptr out_buf, size_t n_bits_to_output) { - if (DO_PRINT_DEBUG) { - std::cout << "encode{out}(): Starting:"; + if (in_buf == 0) { + std::cerr << "encoder::encode: Error: input buffer is NULL.\n"; + assert (0); + } + if (out_buf == 0) { + std::cerr << "encoder::encode: Error: output buffer is NULL.\n"; + assert (0); + } + if (n_bits_to_output == 0) { + std::cerr << "encoder::encode: Warning: no output bits requested.\n"; + return (0); } // set the class-internal number of input bits and // output bits left to encode - size_t saved_n_input_bits; - saved_n_input_bits = d_n_input_bits_left = - compute_n_input_bits (n_bits_to_output); - d_n_output_bits_left = n_bits_to_output; + d_in_buf = in_buf; + d_out_buf = out_buf; + + // check that there are enough output buffer items + + if (d_out_buf->n_items_left() < n_bits_to_output) { + std::cerr << "encoder::encode: Warning: output buffer size (" << + d_out_buf->n_items_left() << "is less than the desired number " + "of output items (" << n_bits_to_output << + ") ... using lower number.\n"; + n_bits_to_output = d_out_buf->n_items_left(); + } + + // check that there are enough input buffer items + + size_t n_bits_to_input = compute_n_input_bits (n_bits_to_output); + + if (d_in_buf->n_items_left() < n_bits_to_input) { + std::cerr << "encoder::encode: Warning: input buffer size (" << + d_in_buf->n_items_left() << "is less than the computed number " + "of required input items (" << n_bits_to_input << + ") ... using lower number.\n"; + n_bits_to_input = d_in_buf->n_items_left(); + n_bits_to_output = compute_n_output_bits (n_bits_to_input); + } if (DO_PRINT_DEBUG) { std::cout << - "# output bits provided = " << d_n_output_bits_left << "\n" - "# input bits computed = " << d_n_input_bits_left << "\n"; + "# output bits = " << n_bits_to_output << "\n" + "# input bits = " << n_bits_to_input << "\n"; } // call the private encode function - encode_private (in_buf, out_buf); + encode_private (); if (DO_PRINT_DEBUG) { std::cout << - "n_input_bits_used = " << - (saved_n_input_bits - d_n_input_bits_left) << "\n" - "n_output_bits_used = " << - (n_bits_to_output - d_n_output_bits_left) << '\n'; + "# input bits used = " << d_in_buf->n_items_used() << "\n" + "# output bits used = " << d_out_buf->n_items_used() << "\n"; } + size_t n_items_used = d_in_buf->n_items_used (); + + // clear these buffers, just in case + + d_in_buf = 0; + d_out_buf = 0; + // return the actual number of input bits used - return (saved_n_input_bits - d_n_input_bits_left); + return (n_items_used); } /* @@ -94,30 +129,76 @@ encoder::encode size_t encoder::encode -(const char** in_buf, +(const code_input_ptr in_buf, size_t n_bits_to_input, - char** out_buf) + code_output_ptr out_buf) { + if (in_buf == 0) { + std::cerr << "encoder::encode: Error: input buffer is NULL.\n"; + assert (0); + } + if (out_buf == 0) { + std::cerr << "encoder::encode: Error: output buffer is NULL.\n"; + assert (0); + } + if (n_bits_to_input == 0) { + std::cerr << "encoder::encode: Warning: no input bits requested.\n"; + return (0); + } + // set the class-internal number of input and // output bits left to encode - size_t saved_n_output_bits; - saved_n_output_bits = d_n_output_bits_left = - compute_n_output_bits (n_bits_to_input); - d_n_input_bits_left = n_bits_to_input; + d_in_buf = in_buf; + d_out_buf = out_buf; + + // check that there are enough input buffer items + + if (d_in_buf->n_items_left() < n_bits_to_input) { + std::cerr << "encoder::encode: Warning: input buffer size (" << + d_in_buf->n_items_left() << "is less than the desired number " + "of input items (" << n_bits_to_input << + ") ... using lower number.\n"; + n_bits_to_input = d_in_buf->n_items_left(); + } + + // check that there are enough output buffer items + + size_t n_bits_to_output = compute_n_output_bits (n_bits_to_input); + + if (d_out_buf->n_items_left() < n_bits_to_output) { + std::cerr << "encoder::encode: Warning: output buffer size (" << + d_out_buf->n_items_left() << "is less than the computed number " + "of required output items (" << n_bits_to_output << + ") ... using lower number.\n"; + n_bits_to_output = d_out_buf->n_items_left(); + n_bits_to_input = compute_n_input_bits (n_bits_to_output); + } + + if (DO_PRINT_DEBUG) { + std::cout << + "# output bits = " << n_bits_to_output << "\n" + "# input bits = " << n_bits_to_input << "\n"; + } // call the private encode function - encode_private (in_buf, out_buf); + encode_private (); if (DO_PRINT_DEBUG) { - std::cout << "n_input_bits_used = " << - (n_bits_to_input - d_n_input_bits_left) << '\n'; - std::cout << "n_output_bits_used = " << - (saved_n_output_bits - d_n_output_bits_left) << '\n'; + std::cout << + "# input bits used = " << d_in_buf->n_items_used() << "\n" + "# output bits used = " << d_out_buf->n_items_used() << "\n"; } + size_t n_items_used = d_out_buf->n_items_used(); + + // clear these buffers, just in case + + d_in_buf = 0; + d_out_buf = 0; + // return the actual number of output bits written - return (saved_n_output_bits - d_n_output_bits_left); + return (n_items_used); } diff --git a/gr-error-correcting-codes/src/lib/libecc/encoder.h b/gr-error-correcting-codes/src/lib/libecc/encoder.h index 2c3dde13a..96ff9f411 100644 --- a/gr-error-correcting-codes/src/lib/libecc/encoder.h +++ b/gr-error-correcting-codes/src/lib/libecc/encoder.h @@ -23,50 +23,68 @@ #ifndef INCLUDED_ENCODER_H #define INCLUDED_ENCODER_H -#include "code_types.h" - -// the 'encoder' class is a virtual class upon which all encoder types -// can be built. +#include "code_io.h" class encoder { + /* + * class encoder + * A virtual class upon which all encoder types can be built. + * This class provides the basic methods and variables + * generic for all encoders. + */ public: encoder () {}; virtual ~encoder () {}; + /* + * compute_n_...: to be defined by inheriting classes, in order to + * allow for user-functions to figure out how many inputs are + * required to generate a given number of outputs, and vice versa. + * Can't define them without knowing the encoder type. + * + * Compute the number of input bits needed to produce 'n_output' bits, + * and the number of output bits which will be produced by 'n_input' + * bits ... for a single stream only. + */ + virtual size_t compute_n_input_bits (size_t n_output_bits) = 0; virtual size_t compute_n_output_bits (size_t n_input_bits) = 0; - virtual size_t encode (const char** in_buf, - char** out_buf, + + /* + * encode: given the input and output buffers, either encode up to + * the number of output bits or encode the number of input bits + * ... if the buffers support either encoding amounts. + */ + + virtual size_t encode (const code_input_ptr in_buf, + code_output_ptr out_buf, size_t n_bits_to_output); - virtual size_t encode (const char** in_buf, + virtual size_t encode (const code_input_ptr in_buf, size_t n_bits_to_input, - char** out_buf); + code_output_ptr out_buf); /* for remote access to internal info */ - inline size_t block_size_bits () {return (d_block_size_bits);}; - inline size_t n_code_inputs () {return (d_n_code_inputs);}; - inline size_t n_code_outputs () {return (d_n_code_outputs);}; + inline const size_t block_size_bits () {return (d_block_size_bits);}; + inline const size_t n_code_inputs () {return (d_n_code_inputs);}; + inline const size_t n_code_outputs () {return (d_n_code_outputs);}; + inline const size_t total_n_enc_bits () {return (d_total_n_enc_bits);}; protected: - /* encode_private: encode the given in_buf and write the output bits + /* + * encode_private: encode the given in_buf and write the output bits * to the out_buf, using internal class variables. This function is * called from the publically available "encode()" methods, which * first set the internal class variables before executing. */ - virtual void encode_private (const char** in_buf, char** out_buf) = 0; - - /* inheriting methods need to figure out what makes the most sense - * for them in terms of getting new inputs and writing outputs. - */ + virtual void encode_private () = 0; size_t d_block_size_bits, d_n_code_inputs, d_n_code_outputs; - size_t d_n_enc_bits, d_total_n_enc_bits; - size_t d_in_buf_ndx, d_out_buf_ndx; - size_t d_in_bit_shift, d_out_bit_shift; - size_t d_n_input_bits_left, d_n_output_bits_left; + size_t d_total_n_enc_bits; + code_input_ptr d_in_buf; + code_output_ptr d_out_buf; }; #endif /* INCLUDED_ENCODER_H */ diff --git a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.cc b/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.cc index b7bd87de0..a4634503b 100644 --- a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.cc +++ b/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.cc @@ -29,16 +29,12 @@ #include #define DO_TIME_THOUGHPUT 0 -#define DO_PRINT_DEBUG 1 #include -#include +//#include -static const int g_max_block_size_bits = 10000000; -static const int g_max_num_streams = 10; -static const int g_num_bits_per_byte = 8; - -void encoder_convolutional::encoder_convolutional_init +void +encoder_convolutional::encoder_convolutional_init (int block_size_bits, int n_code_inputs, int n_code_outputs, @@ -97,14 +93,16 @@ void encoder_convolutional::encoder_convolutional_init d_init_state = start_memory_state; + // reset the inputs and outputs, both to get the correct size() and + // for the sake of zeroing them out. + d_current_inputs.assign (d_n_code_inputs, 0); d_current_outputs.assign (d_n_code_outputs, 0); } void encoder_convolutional::encode_private -(const char** in_buf, - char** out_buf) +() { struct timeval t_tp; if (DO_TIME_THOUGHPUT) { @@ -113,18 +111,12 @@ encoder_convolutional::encode_private // reset buffer indices - d_total_n_enc_bits = d_in_buf_ndx = d_out_buf_ndx = - d_in_bit_shift = d_out_bit_shift = 0; - - if (DO_PRINT_DEBUG) { - std::cout << "Beginning this encode() call; starting parameters.\n"; - std::cout << "d_n_input_bits_left = " << d_n_input_bits_left << '\n'; - std::cout << "d_n_output_bits_left = " << d_n_output_bits_left << '\n'; - } + d_total_n_enc_bits = 0; // while there are inputs and outputs left to process ... - while ((d_n_input_bits_left != 0) & (d_n_output_bits_left != 0)) { + while ((d_in_buf->n_items_left() != 0) & + (d_out_buf->n_items_left() != 0)) { // jump to the correct state in the fsm @@ -158,7 +150,7 @@ encoder_convolutional::encode_private // termination bits, if any), counting down the number of // available input bits. - encode_loop (in_buf, out_buf, &d_n_input_bits_left, d_block_size_bits); + encode_loop (d_in_buf->n_items_left(), d_block_size_bits); // finished this loop; check for jumping to the next state @@ -183,7 +175,12 @@ encoder_convolutional::encode_private // number of output bits left if (d_do_termination == true) { - encode_loop (in_buf, out_buf, &d_n_output_bits_left, d_total_n_delays); + if (d_n_enc_bits == 0) { + // first time through this; save the starting termination state + d_term_state = d_memory; + } + + encode_loop (d_out_buf->n_items_left(), d_total_n_delays); // finished this loop; check for jumping to the next state @@ -207,17 +204,6 @@ encoder_convolutional::encode_private // done (while) there are inputs and outputs } - if (DO_PRINT_DEBUG) { - std::cout << "Done with this encode() call; ending parameters.\n" - "d_in_bit_shift = " << d_in_bit_shift << "\n" - "d_out_bit_shift = " << d_out_bit_shift << "\n" - "d_in_buf_ndx = " << d_in_buf_ndx << "\n" - "d_out_buf_ndx = " << d_out_buf_ndx << "\n" - "d_n_input_bits_left = " << d_n_input_bits_left << "\n" - "d_n_output_bits_left = " << d_n_output_bits_left << "\n" - "d_total_n_enc_bits = " << d_total_n_enc_bits << "\n"; - } - if (DO_TIME_THOUGHPUT) { // compute the throughput for this particular function call u_long d_t = end_timer (&t_tp); @@ -230,28 +216,17 @@ encoder_convolutional::encode_private void encoder_convolutional::encode_loop -(const char** in_buf, - char** out_buf, - size_t* which_counter, +(const size_t& which_counter, size_t how_many) { // generic encode_loop - if (DO_PRINT_DEBUG) { - std::cout << "Starting encode_loop.\n"; - } - - while (((*which_counter) > 0) & (d_n_enc_bits < how_many)) { - if (DO_PRINT_DEBUG) { - std::cout << "*w_c = " << (*which_counter) << ", " - "# enc_bits = " << d_n_enc_bits << " of " << how_many << ".\n" - "Getting new inputs.\n"; - } + while ((which_counter > 0) & (d_n_enc_bits < how_many)) { // get the next set of input bits from all streams; // written into d_current_inputs - get_next_inputs (in_buf); + get_next_inputs (); // use the trellis to do the encoding; // updates the input memory to the new memory state for the given input @@ -261,7 +236,7 @@ encoder_convolutional::encode_loop // write the bits in d_current_outputs into the output buffer - write_output_bits (out_buf); + write_output_bits (); // increment the number of encoded bits for the current block, and // the total number of bits for this running of "encode()" @@ -269,22 +244,88 @@ encoder_convolutional::encode_loop d_n_enc_bits++; d_total_n_enc_bits++; } +} + +size_t +encoder_convolutional::compute_n_output_bits +(size_t n_input_bits) +{ + size_t t_n_output_bits, t_n_input_bits; + t_n_output_bits = t_n_input_bits = n_input_bits; + + if (d_do_termination == true) { + + // not streaming, doing termination; find the number of bits + // currently available with no required inputs, if any + + size_t n_extra = 0; + if (d_fsm_state == fsm_enc_conv_doing_term) { + n_extra = d_total_n_delays - d_n_enc_bits; + } + + t_n_output_bits += n_extra; - if (DO_PRINT_DEBUG) { - std::cout << "ending encode_loop.\n"; + // find the number of blocks using just input bits, + // as well as the number of leftover bits + + size_t t_n_blocks = t_n_input_bits / d_block_size_bits; + size_t t_leftover_bits = t_n_input_bits % d_block_size_bits; + + // add the number of bits*blocks to the number of output bits, as + // well as the number of leftover bits which are not a whole block + + t_n_output_bits += (t_n_blocks * (d_block_size_bits + d_total_n_delays)); + t_n_output_bits += t_leftover_bits; } + + return (t_n_output_bits); } -void -encoder_convolutional::get_next_inputs__term -() +size_t +encoder_convolutional::compute_n_input_bits +(size_t n_output_bits) { - // FIXME: how to figure out which term bit to get? - // loop to set each entry of "d_current_inputs" + size_t t_n_output_bits, t_n_input_bits; + t_n_output_bits = t_n_input_bits = n_output_bits; - // need to do feedback separately, since it involves determining the - // FB bit value & using that as the input value to cancel it out + if (d_do_termination == true) { - d_current_inputs.assign (d_n_code_inputs, 0); - // return (d_term_states[code_input_n] & 1); + // not streaming, doing termination; find the number of bits + // currently available with no required inputs, if any + + size_t n_extra = 0; + if (d_fsm_state == fsm_enc_conv_doing_term) { + n_extra = d_total_n_delays - d_n_enc_bits; + } + + // check to see if this is enough; return 0 if it is. + + if (n_extra >= t_n_output_bits) + return (0); + + // remove those which require no input + + t_n_output_bits -= n_extra; + + // find the number of blocks of data which could be processed + + size_t t_n_output_bits_per_block = d_block_size_bits + d_total_n_delays; + + // get the base number of input items required for the given + // number of blocks to be generated + + size_t t_n_blocks = t_n_output_bits / t_n_output_bits_per_block; + t_n_input_bits = t_n_blocks * d_block_size_bits; + + // add to that the number of leftover inputs needed to generate + // the remainder of the outputs within the remaining block, up to + // the given block size (since anything beyond that within this + // block requires no inputs) + + size_t t_leftover_bits = t_n_output_bits % t_n_output_bits_per_block; + t_n_input_bits += ((t_leftover_bits > d_block_size_bits) ? + d_block_size_bits : t_leftover_bits); + } + + return (t_n_input_bits); } diff --git a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.h b/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.h index 4a0d479ac..11c8b4e69 100644 --- a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.h +++ b/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional.h @@ -126,12 +126,37 @@ public: virtual ~encoder_convolutional () {delete d_trellis;}; +/* + * Compute the number of input bits needed to produce 'n_output' bits, + * and the number of output bits which will be produced by 'n_input' + * bits ... for a single stream only. + * + * For convolutional encoders, there is 1 bit output per bit input per + * stream, with the addition of a some bits for trellis termination if + * selected. Thus the input:output bit ratio will be: + * + * if (streaming | no termination), 1:1 exactly; + * + * if (not streaming & termination), depends on the state of the FSM, + * and needs to include the number of termination bits (the total # of + * delays); ratio is roughly (1:(1+X)), where "X" is the number of + * termination bits divided by the (unterminated) block length in bits. + * + * It's up to the caller to change 'bits' to 'items' ... to know if + * bits are packed (see e.g. code_io "ic8l") or not ("ic1l"), or all + * streams are mux'ed together into one stream. +*/ + + virtual size_t compute_n_input_bits (size_t n_output_bits); + virtual size_t compute_n_output_bits (size_t n_input_bits); + /* for remote access to internal info */ inline const bool do_termination () {return (d_do_termination);}; inline const bool do_feedback () {return (d_trellis->do_feedback());}; inline const bool do_streaming () {return (d_do_streaming);}; inline const size_t total_n_delays () {return (d_total_n_delays);}; + inline const code_convolutional_trellis* trellis() {return (d_trellis);}; protected: /* @@ -161,15 +186,13 @@ protected: int start_memory_state, int end_memory_state); - virtual void encode_private (const char** in_buf, char** out_buf); + virtual void encode_private (); + virtual void encode_loop (const size_t& which_counter, size_t how_many); - virtual void encode_loop (const char** in_buf, char** out_buf, - size_t* which_counter, size_t how_many); - - inline void get_next_inputs (const char** in_buf) { + inline void get_next_inputs () { switch (d_fsm_state) { case fsm_enc_conv_doing_input: - get_next_inputs__input (in_buf); + get_next_inputs__input (); break; case fsm_enc_conv_doing_term: get_next_inputs__term (); @@ -180,7 +203,21 @@ protected: } }; - virtual void get_next_inputs__term (); + inline virtual void get_next_inputs__input () { + d_in_buf->read_items ((void*)(&(d_current_inputs[0]))); + d_in_buf->increment_indices (); + }; + + inline virtual void get_next_inputs__term () { + d_trellis->get_termination_inputs (d_term_state, + d_n_enc_bits, + d_current_inputs); + }; + + inline virtual void write_output_bits () { + d_out_buf->write_items ((const void*)(&(d_current_outputs[0]))); + d_out_buf->increment_indices (); + }; void get_memory_requirements (size_t m, size_t n, @@ -188,13 +225,6 @@ protected: size_t& t_n_unique_fb_prev_start, const std::vector* code_feedback); - // methods which are required by classes which inherit from this - // one; primarily just the parts which deal with getting input bits - // and writing output bits, changing the indices for those buffers. - - virtual void write_output_bits (char** out_buf) = 0; - virtual void get_next_inputs__input (const char** in_buf) = 0; - // variables fsm_enc_conv_t d_fsm_state; @@ -203,7 +233,7 @@ protected: // "total_n_delays" is the total # of delays, needed to determine the // # of states in the decoder - size_t d_total_n_delays; + size_t d_total_n_delays, d_n_enc_bits; // the current state of the encoder (all delays / memories) @@ -225,6 +255,13 @@ protected: // interpreted w/r.t. the actual trellis; memory_t d_init_state; + + // "term_state" is the ending state before termination, used by the + // trellis to determine the correct input-bit sequences needed to + // properly terminate the trellis to the desired end-state; + // used only if doing termination. + + memory_t d_term_state; }; #endif /* INCLUDED_ENCODER_CONVOLUTIONAL_H */ diff --git a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic1_ic1.cc b/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic1_ic1.cc deleted file mode 100644 index aa83c0762..000000000 --- a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic1_ic1.cc +++ /dev/null @@ -1,188 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -#define DO_PRINT_DEBUG 0 - -static const int g_num_bits_per_byte = 8; - -// FIXME -size_t -encoder_convolutional_ic1_ic1::compute_n_output_bits -(size_t n_input_bits) -{ - assert (0); - return (0); -} - -/* - * Compute the number of input bits needed to produce - * 'n_output' bits. For convolutional encoders, there is - * 1 bit output per bit input per stream, with the addition of a some - * bits for trellis termination if selected. Thus the input:output - * bit ratio will be: - * - * if (streaming | no termination), 1:1 - * - * if (not streaming & termination), roughly 1:(1+X), where "X" is the - * total memory size of the code divided by the block length in bits. - * But this also depends on the state of the FSM ... how many bits are - * left before termination. - * - * The returned value will also depend on whether bits are packed, as - * well as whether streams are mux'ed together. - */ - -size_t -encoder_convolutional_ic1_ic1::compute_n_input_bits -(size_t n_output_bits) -{ - size_t t_n_output_bits, t_n_input_bits; - t_n_output_bits = t_n_input_bits = n_output_bits; - - if (d_do_termination == true) { - - // not streaming, doing termination; find the number of bits - // currently available with no required inputs, if any - - size_t n_extra = 0; - if (d_fsm_state == fsm_enc_conv_doing_term) { - n_extra = d_total_n_delays - d_n_enc_bits; - } - - // check to see if this is enough; return 0 if it is. - - if (n_extra >= t_n_output_bits) - return (0); - - // remove those which require no input - - t_n_output_bits -= n_extra; - - // find the number of blocks of data which could be processed - - size_t t_n_output_bits_per_block = d_block_size_bits + d_total_n_delays; - - // get the base number of input items required for the given - // number of blocks to be generated - - size_t t_n_blocks = t_n_output_bits / t_n_output_bits_per_block; - t_n_input_bits = t_n_blocks * d_block_size_bits; - - // add to that the number of leftover inputs needed to generate - // the remainder of the outputs within the remaining block, up to - // the given block size (since anything beyond that within this - // block requires no inputs) - - size_t t_leftover_bits = t_n_output_bits % t_n_output_bits_per_block; - t_n_input_bits += ((t_leftover_bits > d_block_size_bits) ? - d_block_size_bits : t_leftover_bits); - } - - return (t_n_input_bits); -} - -void -encoder_convolutional_ic1_ic1::write_output_bits -(char** out_buf) -{ - // write all the outputs bits in d_current_outputs LSB (&1) to the - // given output buffer. - - // one bit per output 'char' for "ic1" type output - - for (size_t n = 0; n < d_n_code_outputs; n++) { - if (DO_PRINT_DEBUG) { - std::cout << "Starting output_bit:\n" - " O_i[" << n << "][" << d_out_buf_ndx << "] = " << - n2bs (out_buf[n][d_out_buf_ndx], g_num_bits_per_byte) << - ", b_out = " << n2bs (d_current_outputs[n], 1) << ", "; - } - - out_buf[n][d_out_buf_ndx] = d_current_outputs[n]; - - if (DO_PRINT_DEBUG) { - std::cout << "O_o[][] = " << - n2bs (out_buf[n][d_out_buf_ndx], g_num_bits_per_byte) << - "\n"; - } - } - - if (DO_PRINT_DEBUG) { - std::cout << "Ending write_output_bits.\n"; - } - - // decrement the number of output bits left on all streams - - d_n_output_bits_left--; - - // increment the output index (not the bit shift index) for the next - // write - - d_out_buf_ndx++; -} - -void -encoder_convolutional_ic1_ic1::get_next_inputs__input -(const char** in_buf) -{ - // get the next set of input bits, moved into the LSB (&1) of - // d_current_inputs - - // one bit per input 'char' for "ic1" type input - - for (size_t m = 0; m < d_n_code_inputs; m++) { - d_current_inputs[m] = ((in_buf[m][d_in_buf_ndx]) & 1); - - if (DO_PRINT_DEBUG) { - std::cout << "I[" << m << "][" << d_in_buf_ndx << "] = " << - n2bs (d_current_inputs[m], 1) << "\n"; - } - } - - // decrement the number of bits left on all streams - - if (DO_PRINT_DEBUG) { - std::cout << "# in bits left: " << d_n_input_bits_left << - " -> " << (d_n_input_bits_left-1) << "\n"; - } - - d_n_input_bits_left--; - - // increment the input index (not the bit shift index) for the next - // read - - if (DO_PRINT_DEBUG) { - std::cout << "# in buf ndx: " << d_in_buf_ndx << - " -> " << (d_in_buf_ndx+1) << "\n"; - } - - d_in_buf_ndx++; -} diff --git a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic1_ic1.h b/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic1_ic1.h deleted file mode 100644 index a742b097a..000000000 --- a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic1_ic1.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef INCLUDED_ENCODER_CONVOLUTIONAL_IC1_IC1_H -#define INCLUDED_ENCODER_CONVOLUTIONAL_IC1_IC1_H - -#include "encoder_convolutional.h" - -class encoder_convolutional_ic1_ic1 : public encoder_convolutional -{ -public: -/*! - * class encoder_convolutional_ic1_ic1 : public encoder_convolutional - * - * Encode the incoming streams using a convolutional encoder, - * "feedforward" or feedback. Optional termination, data - * streaming, and starting and ending memory states. - * - * input is "ic1": streams of char, one stream per input as defined by the - * instantiated code, using only the right-most justified bit as - * the single input bit per input item. - * - * output is "ic1": streams of char, one stream per output as defined by the - * instantiated code, using only the right-most justified bit as - * the single output bit per output item. - */ - - encoder_convolutional_ic1_ic1 - (int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generators, - bool do_termination = true, - int start_memory_state = 0, - int end_memory_state = 0) - : encoder_convolutional (frame_size_bits, - n_code_inputs, - n_code_outputs, - code_generators, - do_termination, - start_memory_state, - end_memory_state) {}; - - encoder_convolutional_ic1_ic1 - (int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generators, - const std::vector &code_feedback, - bool do_termination = true, - int start_memory_state = 0, - int end_memory_state = 0) - : encoder_convolutional (frame_size_bits, - n_code_inputs, - n_code_outputs, - code_generators, - code_feedback, - do_termination, - start_memory_state, - end_memory_state) {}; - - virtual ~encoder_convolutional_ic1_ic1 () {}; - - virtual size_t compute_n_input_bits (size_t n_output_bits); - virtual size_t compute_n_output_bits (size_t n_input_bits); - -protected: - virtual void get_next_inputs__input (const char** in_buf); - virtual void write_output_bits (char** out_buf); -}; - -#endif /* INCLUDED_ENCODER_CONVOLUTIONAL_IC1_IC1_H */ diff --git a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic8_ic8.cc b/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic8_ic8.cc deleted file mode 100644 index 5d2a4bbbd..000000000 --- a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic8_ic8.cc +++ /dev/null @@ -1,224 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include - -#define DO_TIME_THOUGHPUT 1 -#define DO_PRINT_DEBUG 1 - -#if DO_TIME_THOUGHPUT -#include -#endif -#if DO_PRINT_DEBUG -#include -#endif - -// FIXME: when doing packed, should probably allow user to select how -// bits are selected, so-as to make sure it's always the same -// no matter the CPU endianness - -// FIXME -size_t -encoder_convolutional_ic8_ic8::compute_n_output_bits -(size_t n_input_bits) -{ - assert (0); - return (0); -} - -/* - * Compute the number of input bits needed to produce - * 'n_output' bits. For convolutional encoders, there is - * 1 bit output per bit input per stream, with the addition of a some - * bits for trellis termination if selected. Thus the input:output - * bit ratio will be: - * - * if (streaming | no termination), 1:1 - * - * if (not streaming & termination), roughly 1:(1+X), where "X" is the - * total memory size of the code divided by the block length in bits. - * But this also depends on the state of the FSM ... how many bits are - * left before termination. - * - * The returned value will also depend on whether bits are packed, as - * well as whether streams are mux'ed together. - */ - -size_t -encoder_convolutional_ic8_ic8::compute_n_input_bits -(size_t n_output_bits) -{ - size_t t_n_output_bits, t_n_input_bits; - t_n_output_bits = t_n_input_bits = n_output_bits; - - if (d_do_termination == true) { - - // not streaming, doing termination; find the number of bits - // currently available with no required inputs, if any - - size_t n_extra = 0; - if (d_fsm_state == fsm_enc_conv_doing_term) { - n_extra = d_max_memory - d_n_enc_bits; - } - - // check to see if this is enough; return 0 if it is. - - if (n_extra >= t_n_output_bits) - return (0); - - // remove those which require no input - - t_n_output_bits -= n_extra; - - // find the number of frames of data which could be processed - - size_t t_n_output_bits_per_frame = d_frame_size_bits + d_max_memory; - - // get the base number of input items required for the given - // number of frames to be generated - - size_t t_n_frames = t_n_output_bits / t_n_output_bits_per_frame; - t_n_input_bits = t_n_frames * d_frame_size_bits; - - // add to that the number of leftover inputs needed to generate - // the remainder of the outputs within the remaining frame, up to - // the given frame size (since anything beyond that within this - // frame requires no inputs) - - size_t t_leftover_bits = t_n_output_bits % t_n_output_bits_per_frame; - t_n_input_bits += ((t_leftover_bits > d_frame_size_bits) ? - d_frame_size_bits : t_leftover_bits); - } - - return (t_n_input_bits); -} - -void -encoder_convolutional_ic8_ic8::increment_io_indices -(bool while_encoding) -{ - // increment the buffer index only for this version, only after - // encoding is done and all resulting outputs are stored on the - // output streams - - if (while_encoding == false) { - d_out_buf_ndx++; - d_in_buf_ndx++; - } - - // nothing to do while encoding, so no else - -#if 0 -// move counters to the next input bit, wrapping to the next input -// byte as necessary - if (++d_in_bit_shift % g_num_bits_per_byte == 0) { - d_in_bit_shift = 0; - d_in_buf_ndx++; - } -// move counters to the next output bit, wrapping to the next output -// byte as necessary - if (++d_out_bit_shift % g_num_bits_per_byte == 0) { - d_out_bit_shift = 0; - d_out_buf_ndx++; - } -#endif -} - -void -encoder_convolutional_ic8_ic8::output_bit -(char t_out_bit, - char** out_buf, - size_t t_output_stream) -{ - // store the result for this particular output stream - // one bit per output item for "ic8" type output - - if (DO_PRINT_DEBUG) { - std::cout << ", O_i[" << t_output_stream << - "][" << d_out_buf_ndx << "] = " << - n2bs (out_buf[t_output_stream][d_out_buf_ndx], 2); - } - - out_buf[t_output_stream][d_out_buf_ndx] = t_out_bit; - - if (DO_PRINT_DEBUG) { - std::cout << ", b_out = " << t_out_bit << - ", O_o[" << t_output_stream << "][" << d_out_buf_ndx << "][" << - d_out_bit_shift << "] = " << - n2bs (out_buf[t_output_stream][d_out_buf_ndx], 2) << '\n'; - } - -#if 0 -#if DO_PRINT_DEBUG - std::cout << ", O_i[" << t_output_stream << - "][" << d_out_buf_ndx << "] = " << - n2bs (out_buf[t_output_stream][d_out_buf_ndx], g_num_bits_per_byte); -#endif - -// packed bits in each output item - out_buf[t_output_stream][d_out_buf_ndx] |= - (t_out_bit << d_out_bit_shift); - -#if DO_PRINT_DEBUG - std::cout << ", b_out = " << t_out_bit << - ", O_o[" << t_output_stream << "][" << d_out_buf_ndx << "][" << - d_out_bit_shift << "] = " << - n2bs (out_buf[t_output_stream][d_out_buf_ndx], g_num_bits_per_byte) << '\n'; -#endif -#endif -} - -char -encoder_convolutional_ic8_ic8::get_next_bit__input -(const char** in_buf, - size_t code_input_n) -{ - // get a bit from this particular input stream - // one bit per output item for "ic8" type input - - if (DO_PRINT_DEBUG) { - std::cout << "I[" << p << "][" << d_in_buf_ndx << "] = "; - cout_binary (t_next_bit, g_num_bits_per_byte); - std::cout << ", st_i[" << p << "] = "; - cout_binary ((*t_states_ptr), d_max_memory+2); - std::cout << ", I[" << p << "][" << d_in_buf_ndx << "][" << - d_in_bit_shift << "] = " << t_next_bit << - ", st_o[" << p << "] = "; - cout_binary (t_state, d_max_memory+2); - std::cout << '\n'; - } - - return ((in_buf[code_input_n][d_in_buf_ndx] >> d_in_bit_shift) & 1); -} - -char -encoder_convolutional_ic8_ic8::get_next_bit__term -(size_t code_input_n) -{ - return ((d_term_states[code_input_n] >> d_in_bit_shift) & 1); -} diff --git a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic8_ic8.h b/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic8_ic8.h deleted file mode 100644 index dad39400c..000000000 --- a/gr-error-correcting-codes/src/lib/libecc/encoder_convolutional_ic8_ic8.h +++ /dev/null @@ -1,96 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * GNU Radio is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU Radio; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef INCLUDED_ENCODER_CONVOLUTIONAL_IC8_IC8_H -#define INCLUDED_ENCODER_CONVOLUTIONAL_IC8_IC8_H - -#include "encoder_convolutional.h" - -/*! - * class encoder_convolutional_ic8_ic8 : public encoder_convolutional - * - * Encode the incoming streams using a convolutional encoder, - * "feedforward" or feedback. Optional termination, data - * streaming, and starting and ending memory states. - * - * input is "ic8": streams of char, one stream per input as defined by the - * instantiated code, using all 8 bits in the char. - * - * FIXME: need to have inputs for MSB or LSB first input and output. - * - * output is "ic8": streams of char, one stream per output as defined by the - * instantiated code, using all 8 bits in the char. - */ - -class encoder_convolutional_ic8_ic8 : public encoder_convolutional -{ -public: - encoder_convolutional_ic8_ic8 - (int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generators, - bool do_termination = true, - int start_memory_state = 0, - int end_memory_state = 0) - : encoder_convolutional (frame_size_bits, - n_code_inputs, - n_code_outputs, - code_generators, - do_termination, - start_memory_state, - end_memory_state) {}; - - encoder_convolutional_ic8_ic8 - (int frame_size_bits, - int n_code_inputs, - int n_code_outputs, - const std::vector &code_generators, - const std::vector &code_feedback, - bool do_termination = true, - int start_memory_state = 0, - int end_memory_state = 0) - : encoder_convolutional (frame_size_bits, - n_code_inputs, - n_code_outputs, - code_generators, - code_feedback, - do_termination, - start_memory_state, - end_memory_state) {}; - - virtual ~encoder_convolutional_ic8_ic8 () {}; - - virtual size_t compute_n_input_bits (size_t n_output_bits); - virtual size_t compute_n_output_bits (size_t n_input_bits); - -protected: - virtual char get_next_bit__input (const char** in_buf, - size_t code_input_n); - virtual char get_next_bit__term (size_t code_input_n); - virtual void output_bit (char t_out_bit, char** out_buf, - size_t t_output_stream); - virtual void increment_io_indices (bool while_encoding); - virtual void update_memory_post_encode (); -}; - -#endif /* INCLUDED_ENCODER_CONVOLUTIONAL_IC8_IC8_H */ diff --git a/gr-error-correcting-codes/src/lib/libecc/encoder_turbo.cc b/gr-error-correcting-codes/src/lib/libecc/encoder_turbo.cc index 3f528cb91..fc14ac51d 100644 --- a/gr-error-correcting-codes/src/lib/libecc/encoder_turbo.cc +++ b/gr-error-correcting-codes/src/lib/libecc/encoder_turbo.cc @@ -1,52 +1,41 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include "encoder_turbo.h" encoder_turbo::encoder_turbo (int n_code_inputs, int n_code_outputs, - const std::vector &encoders, - const std::vector &interleavers) + const std::vector& encoders, + const std::vector& interleavers) { - // need error checking on inputs + // need error checking on inputs, not yet. +#if 0 d_encoders = encoders; d_interleavers = interleavers; -} - -// dummy stuff for now to test std::vector stuff - -size_t -encoder_turbo::compute_n_input_bits -(size_t n_output_bits) -{ - return (0); -} - -size_t -encoder_turbo::compute_n_output_bits -(size_t n_input_bits) -{ - return (0); -} - -void -encoder_turbo::encode_private -(const char** in_buf, - char** out_buf) -{ -} - -char -encoder_turbo::get_next_bit -(const char** in_buf, - size_t code_input_n) -{ - return (0); -} - -void -encoder_turbo::output_bit -(char t_out_bit, - char** out_buf, - size_t t_output_stream) -{ +#endif } diff --git a/gr-error-correcting-codes/src/lib/libecc/encoder_turbo.h b/gr-error-correcting-codes/src/lib/libecc/encoder_turbo.h index 8c295f1e5..982ce7951 100644 --- a/gr-error-correcting-codes/src/lib/libecc/encoder_turbo.h +++ b/gr-error-correcting-codes/src/lib/libecc/encoder_turbo.h @@ -24,7 +24,8 @@ #define INCLUDED_ENCODER_TURBO_H #include "encoder_convolutional.h" -#include + +typedef std::vector interleaver_t; class encoder_turbo : public encoder { @@ -53,18 +54,19 @@ public: encoder_turbo (int n_code_inputs, int n_code_outputs, - const std::vector &encoders, - const std::vector &interleavers); + const std::vector& encoders, + const std::vector& interleavers); virtual ~encoder_turbo () {}; /* for remote access to internal info */ - inline bool do_termination () {return (d_do_termination);}; + inline const bool do_termination () {return (d_do_termination);}; #if 1 - virtual size_t compute_n_input_bits (size_t n_output_bits); - virtual size_t compute_n_output_bits (size_t n_input_bits); + // dummy functions for now + virtual size_t compute_n_input_bits (size_t n_output_bits){return(0);}; + virtual size_t compute_n_output_bits (size_t n_input_bits){return(0);}; #endif protected: @@ -84,44 +86,15 @@ protected: fsm_enc_turbo_init, fsm_enc_turbo_doing_input, fsm_enc_turbo_doing_term }; -/* - * maio(i,o): matrix access into a vector, knowing the # of code - * outputs (from inside the class). References into a vector with - * code inputs ordered by code output. - * - * 'i' is the first dimension - immediate memory order first - the code input - * 'o' is the second dimension - slower memory order second - the code output - * - * returns ((o*n_code_outputs) + i) - */ - - inline size_t maio(size_t i, size_t o) {return ((o*d_n_code_outputs) + i);}; - -/* - * maoi(i,o): matrix access into a vector, knowing the # of code - * inputs (from inside the class). References into a vector with - * code outputs ordered by code input. - * - * 'o' is the first dimension - immediate memory order first - the code output - * 'i' is the second dimension - slower memory order second - the code input - * - * returns ((i*n_code_inputs) + o) - */ - - inline size_t maoi(size_t i, size_t o) {return ((i*d_n_code_inputs) + o);}; - // methods defined in this class #if 1 // temporary just to get full compilation - virtual void encode_private (const char** in_buf, char** out_buf); - virtual char get_next_bit (const char** in_buf, size_t code_input_n); - virtual void output_bit (char t_out_bit, char** out_buf, - size_t t_output_stream); + virtual void encode_private () {}; + #else - virtual void encode_private (const char** in_buf, char** out_buf) = 0; - virtual void encode_loop (const char** in_buf, char** out_buf, - size_t* which_counter, size_t how_many) = 0; + virtual void encode_private () = 0; + virtual void encode_loop (size_t* which_counter, size_t how_many) = 0; virtual char get_next_bit (const char** in_buf, size_t code_input_n) = 0; virtual char get_next_bit__term (size_t code_input_n) = 0; @@ -131,7 +104,6 @@ protected: virtual char get_next_bit__input (const char** in_buf, size_t code_input_n) = 0; - virtual void increment_io_indices (bool while_encoding) = 0; #endif // variables diff --git a/gr-error-correcting-codes/src/lib/libecc/mld/Makefile.am b/gr-error-correcting-codes/src/lib/libecc/mld/Makefile.am index b5accd5af..1b816aafd 100644 --- a/gr-error-correcting-codes/src/lib/libecc/mld/Makefile.am +++ b/gr-error-correcting-codes/src/lib/libecc/mld/Makefile.am @@ -21,7 +21,7 @@ include $(top_srcdir)/Makefile.common -INCLUDES = $(STD_DEFINES_AND_INCLUDES) -I.. -I../.. +INCLUDES = $(STD_DEFINES_AND_INCLUDES) noinst_LTLIBRARIES = libmld.la diff --git a/gr-error-correcting-codes/src/lib/libecc/mld/n2bs.cc b/gr-error-correcting-codes/src/lib/libecc/mld/n2bs.cc index 909aa0867..99e95a5d2 100644 --- a/gr-error-correcting-codes/src/lib/libecc/mld/n2bs.cc +++ b/gr-error-correcting-codes/src/lib/libecc/mld/n2bs.cc @@ -2,10 +2,8 @@ /* * Copyright 2006 Free Software Foundation, Inc. * - * This file is part of GNU Radio. + * This file is part of GNU Radio * - * Primary Author: Michael Dickens, NCIP Lab, University of Notre Dame - * * 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) @@ -24,13 +22,12 @@ #include #include +#include "../code_types.h" const int g_num_bits_per_byte = 8; -std::string n2bs (long long number, size_t digits) +std::string DoIt (int64_t number, size_t digits) { - if (digits > (sizeof (long long) * g_num_bits_per_byte)) - digits = sizeof (long long); std::string retVal (digits, '0'); if (number != 0) for (int n = --digits; n >= 0; n--) { @@ -41,29 +38,66 @@ std::string n2bs (long long number, size_t digits) } return (retVal); } -std::string n2bs (char number, size_t digits) + +std::string n2bs (int64_t number, size_t digits) +{ + if (digits > (sizeof (int64_t) * g_num_bits_per_byte)) + digits = sizeof (int64_t); + return DoIt (number, digits); +} +std::string n2bs (int8_t number, size_t digits) { - if (digits > (sizeof (char) * g_num_bits_per_byte)) - digits = sizeof (char); - return n2bs ((long long) number, digits); + if (digits > (sizeof (int8_t) * g_num_bits_per_byte)) + digits = sizeof (int8_t); + return DoIt ((int64_t) number, digits); } -std::string n2bs (int number, size_t digits) +std::string n2bs (int16_t number, size_t digits) { - if (digits > (sizeof (int) * g_num_bits_per_byte)) - digits = sizeof (int); - return n2bs ((long long) number, digits); + if (digits > (sizeof (int16_t) * g_num_bits_per_byte)) + digits = sizeof (int16_t); + return DoIt ((int64_t) number, digits); +} +std::string n2bs (int32_t number, size_t digits) +{ + if (digits > (sizeof (int32_t) * g_num_bits_per_byte)) + digits = sizeof (int32_t); + return DoIt ((int64_t) number, digits); } std::string n2bs (long number, size_t digits) { if (digits > (sizeof (long) * g_num_bits_per_byte)) digits = sizeof (long); - return n2bs ((long long) number, digits); + return DoIt ((int64_t) number, digits); +} +std::string n2bs (u_int8_t number, size_t digits) +{ + if (digits > (sizeof (u_int8_t) * g_num_bits_per_byte)) + digits = sizeof (u_int8_t); + return DoIt ((int64_t) number, digits); +} +std::string n2bs (u_int16_t number, size_t digits) +{ + if (digits > (sizeof (u_int16_t) * g_num_bits_per_byte)) + digits = sizeof (u_int16_t); + return DoIt ((int64_t) number, digits); +} +std::string n2bs (u_int32_t number, size_t digits) +{ + if (digits > (sizeof (u_int32_t) * g_num_bits_per_byte)) + digits = sizeof (u_int32_t); + return DoIt ((int64_t) number, digits); +} +std::string n2bs (unsigned long number, size_t digits) +{ + if (digits > (sizeof (unsigned long) * g_num_bits_per_byte)) + digits = sizeof (unsigned long); + return DoIt ((int64_t) number, digits); } -std::string n2bs (size_t number, size_t digits) +std::string n2bs (u_int64_t number, size_t digits) { - if (digits > (sizeof (size_t) * g_num_bits_per_byte)) - digits = sizeof (size_t); - return n2bs ((long long) number, digits); + if (digits > (sizeof (u_int64_t) * g_num_bits_per_byte)) + digits = sizeof (u_int64_t); + return DoIt ((int64_t) number, digits); } void cout_binary (int number, int digits) diff --git a/gr-error-correcting-codes/src/lib/libecc/mld/n2bs.h b/gr-error-correcting-codes/src/lib/libecc/mld/n2bs.h index a663dce8a..16ef4d758 100644 --- a/gr-error-correcting-codes/src/lib/libecc/mld/n2bs.h +++ b/gr-error-correcting-codes/src/lib/libecc/mld/n2bs.h @@ -2,10 +2,8 @@ /* * Copyright 2006 Free Software Foundation, Inc. * - * This file is part of GNU Radio. + * This file is part of GNU Radio * - * Primary Author: Michael Dickens, NCIP Lab, University of Notre Dame - * * 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) @@ -22,11 +20,26 @@ * Boston, MA 02111-1307, USA. */ +#ifndef INCLUDED_N2BS_H +#define INCLUDED_N2BS_H + #include -extern std::string n2bs (char number, size_t digits); -extern std::string n2bs (int number, size_t digits); -extern std::string n2bs (long number, size_t digits); -extern std::string n2bs (size_t number, size_t digits); -extern std::string n2bs (long long number, size_t digits); -extern void cout_binary (int number, int digits); +std::string n2bs (int8_t number, size_t digits); +std::string n2bs (int16_t number, size_t digits); +std::string n2bs (int32_t number, size_t digits); +#if 1 +std::string n2bs (long number, size_t digits); +#endif +std::string n2bs (int64_t number, size_t digits); +std::string n2bs (u_int8_t number, size_t digits); +std::string n2bs (u_int16_t number, size_t digits); +std::string n2bs (u_int32_t number, size_t digits); +#if 1 +std::string n2bs (unsigned long number, size_t digits); +#endif +std::string n2bs (u_int64_t number, size_t digits); + +void cout_binary (int number, int digits); + +#endif /* INCLUDED_N2BS_H */ diff --git a/gr-error-correcting-codes/src/lib/libecc/tests/Makefile.am b/gr-error-correcting-codes/src/lib/libecc/tests/Makefile.am index 79850ba74..2be5a8c2b 100644 --- a/gr-error-correcting-codes/src/lib/libecc/tests/Makefile.am +++ b/gr-error-correcting-codes/src/lib/libecc/tests/Makefile.am @@ -21,7 +21,8 @@ include $(top_srcdir)/Makefile.common -INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES) -I.. +INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(CPPUNIT_INCLUDES) \ + -I$(top_srcdir)/gr-error-correcting-codes/src/lib/libecc noinst_LTLIBRARIES = libecc-qa.la diff --git a/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.cc b/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.cc index 6ea72b6f8..7e9e1c37c 100644 --- a/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.cc +++ b/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.cc @@ -20,7 +20,7 @@ * Boston, MA 02111-1307, USA. */ -#include "encoder_convolutional_ic1_ic1.h" +#include "encoder_convolutional.h" #include #include #include @@ -28,11 +28,12 @@ #include #include - void qa_encoder_convolutional_ic1_ic1::do_encoder_check -(const char** c_in, +(int test_n, + const char** c_in, const char** c_res, + int n_input_items, int n_output_items, int block_size_bits, int n_code_inputs, @@ -45,7 +46,7 @@ qa_encoder_convolutional_ic1_ic1::do_encoder_check for (int m = 0; m < n_code_inputs * n_code_outputs; m++) t_code_generators[m] = code_generators[m]; - encoder_convolutional_ic1_ic1* t_encoder; + encoder_convolutional* t_encoder; if (code_feedback) { std::vector t_code_feedback; @@ -53,33 +54,48 @@ qa_encoder_convolutional_ic1_ic1::do_encoder_check for (int m = 0; m < n_code_inputs * n_code_outputs; m++) t_code_feedback[m] = code_feedback[m]; - t_encoder = new encoder_convolutional_ic1_ic1 + t_encoder = new encoder_convolutional (block_size_bits, n_code_inputs, n_code_outputs, t_code_generators, t_code_feedback); } else { - t_encoder = new encoder_convolutional_ic1_ic1 + t_encoder = new encoder_convolutional (block_size_bits, n_code_inputs, n_code_outputs, t_code_generators); } + code_input_ic1l* t_c_in = new code_input_ic1l (n_code_inputs); + t_c_in->set_buffer ((void**) c_in, n_input_items); + char** t_out = new char*[n_code_outputs]; for (int m = 0; m < n_code_outputs; m++) { t_out[m] = new char[n_output_items]; } - t_encoder->encode (c_in, (char**) t_out, n_output_items); + code_output_ic1l* t_c_out = new code_output_ic1l (n_code_outputs); + t_c_out->set_buffer ((void**) t_out, n_output_items); + + t_encoder->encode (t_c_in, t_c_out, n_output_items); for (int m = 0; m < n_code_outputs; m++) { for (int n = 0; n < n_output_items; n++) { + if (c_res[m][n] != t_out[m][n]) { + std::cout << "Test " << test_n << ": Item [" << m << + "][" << n << "] not equal: des = " << (int)(c_res[m][n]) << + ", act = " << (int)(t_out[m][n]) << "\n"; + } CPPUNIT_ASSERT_EQUAL (c_res[m][n], t_out[m][n]); } } + delete t_c_out; + t_c_out = 0; + delete t_c_in; + t_c_in = 0; delete t_encoder; t_encoder = 0; @@ -122,9 +138,10 @@ void qa_encoder_convolutional_ic1_ic1::t0 () { - do_encoder_check ((const char**) t0_in, (const char**) t0_res, - t0_n_output_items, 100, t0_n_code_inputs, - t0_n_code_outputs, (const int*) t0_code_generator); + do_encoder_check (0, (const char**) t0_in, (const char**) t0_res, + t0_n_input_items, t0_n_output_items, 100, + t0_n_code_inputs, t0_n_code_outputs, + (const int*) t0_code_generator); } // TEST 1 @@ -158,9 +175,10 @@ void qa_encoder_convolutional_ic1_ic1::t1 () { - do_encoder_check ((const char**) t1_in, (const char**) t1_res, - t1_n_output_items, 100, t1_n_code_inputs, - t1_n_code_outputs, (const int*) t1_code_generator); + do_encoder_check (1, (const char**) t1_in, (const char**) t1_res, + t1_n_input_items, t1_n_output_items, 100, + t1_n_code_inputs, t1_n_code_outputs, + (const int*) t1_code_generator); } // TEST 2 @@ -195,9 +213,10 @@ void qa_encoder_convolutional_ic1_ic1::t2 () { - do_encoder_check ((const char**) t2_in, (const char**) t2_res, - t2_n_output_items, 100, t2_n_code_inputs, - t2_n_code_outputs, (const int*) t2_code_generator, + do_encoder_check (2, (const char**) t2_in, (const char**) t2_res, + t2_n_input_items, t2_n_output_items, 100, + t2_n_code_inputs, t2_n_code_outputs, + (const int*) t2_code_generator, (const int*) t2_code_feedback); } @@ -233,9 +252,10 @@ void qa_encoder_convolutional_ic1_ic1::t3 () { - do_encoder_check ((const char**) t3_in, (const char**) t3_res, - t3_n_output_items, 100, t3_n_code_inputs, - t3_n_code_outputs, (const int*) t3_code_generator, + do_encoder_check (3, (const char**) t3_in, (const char**) t3_res, + t3_n_input_items, t3_n_output_items, 100, + t3_n_code_inputs, t3_n_code_outputs, + (const int*) t3_code_generator, (const int*) t3_code_feedback); } @@ -271,9 +291,10 @@ void qa_encoder_convolutional_ic1_ic1::t4 () { - do_encoder_check ((const char**) t4_in, (const char**) t4_res, - t4_n_output_items, 100, t4_n_code_inputs, - t4_n_code_outputs, (const int*) t4_code_generator, + do_encoder_check (4, (const char**) t4_in, (const char**) t4_res, + t4_n_input_items, t4_n_output_items, 100, + t4_n_code_inputs, t4_n_code_outputs, + (const int*) t4_code_generator, (const int*) t4_code_feedback); } @@ -310,9 +331,10 @@ qa_encoder_convolutional_ic1_ic1::t5 () { #if 0 - do_encoder_check ((const char**) t5_in, (const char**) t5_res, - t5_n_output_items, 100, t5_n_code_inputs, - t5_n_code_outputs, (const int*) t5_code_generator); + do_encoder_check (5, (const char**) t5_in, (const char**) t5_res, + t5_n_input_items, t5_n_output_items, 100, + t5_n_code_inputs, t5_n_code_outputs, + (const int*) t5_code_generator); #endif } @@ -346,8 +368,8 @@ void qa_encoder_convolutional_ic1_ic1::t6 () { - do_encoder_check ((const char**) t6_in, (const char**) t6_res, - t6_n_output_items, 5, t6_n_code_inputs, + do_encoder_check (6, (const char**) t6_in, (const char**) t6_res, + t6_n_input_items, t6_n_output_items, 5, t6_n_code_inputs, t6_n_code_outputs, (const int*) t6_code_generator); } @@ -383,8 +405,8 @@ qa_encoder_convolutional_ic1_ic1::t7 () { #if 0 - do_encoder_check ((const char**) t7_in, (const char**) t7_res, - t7_n_output_items, 5, t7_n_code_inputs, + do_encoder_check (7, (const char**) t7_in, (const char**) t7_res, + t7_n_input_items, t7_n_output_items, 5, t7_n_code_inputs, t7_n_code_outputs, (const int*) t7_code_generator, (const int*) t7_code_feedback); #endif @@ -422,8 +444,8 @@ qa_encoder_convolutional_ic1_ic1::t8 () { #if 0 - do_encoder_check ((const char**) t8_in, (const char**) t8_res, - t8_n_output_items, 5, t8_n_code_inputs, + do_encoder_check (8, (const char**) t8_in, (const char**) t8_res, + t8_n_input_items, t8_n_output_items, 5, t8_n_code_inputs, t8_n_code_outputs, (const int*) t8_code_generator, (const int*) t8_code_feedback); #endif diff --git a/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.h b/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.h index 4449e9eb8..64ab3ab5f 100644 --- a/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.h +++ b/gr-error-correcting-codes/src/lib/libecc/tests/qa_encoder_convolutional_ic1_ic1.h @@ -42,8 +42,10 @@ class qa_encoder_convolutional_ic1_ic1 : public CppUnit::TestCase { CPPUNIT_TEST_SUITE_END (); private: - void do_encoder_check (const char** c_t1_in, + void do_encoder_check (int test_n, + const char** c_t1_in, const char** c_t1_res, + int n_input_items, int n_output_items, int block_size_bits, int n_code_inputs, -- cgit