[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] gr-error-correcting-codes/src/lib Makefile.am _...
From: |
Michael Dickens |
Subject: |
[Commit-gnuradio] gr-error-correcting-codes/src/lib Makefile.am _... |
Date: |
Mon, 03 Jul 2006 02:12:54 +0000 |
CVSROOT: /sources/gnuradio
Module name: gr-error-correcting-codes
Changes by: Michael Dickens <michaelld> 06/07/03 02:12:53
Added files:
src/lib : Makefile.am __init__.py ecc.i
gr_decoder_viterbi_block_soft_full.cc
gr_decoder_viterbi_block_soft_full.h
gr_decoder_viterbi_block_soft_full.i
gr_streams_encode_convolutional.cc
gr_streams_encode_convolutional.h
gr_streams_encode_convolutional.i
gr_syms_to_metrics.cc gr_syms_to_metrics.h
gr_syms_to_metrics.i qa_ecc.py
Log message:
Initial checkin. Work in progress. More blocks coming.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/Makefile.am?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/__init__.py?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/ecc.i?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_soft_full.cc?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_soft_full.h?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_decoder_viterbi_block_soft_full.i?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.cc?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.h?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_streams_encode_convolutional.i?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.cc?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.h?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/gr_syms_to_metrics.i?cvsroot=gnuradio&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/gr-error-correcting-codes/src/lib/qa_ecc.py?cvsroot=gnuradio&rev=1.1
Patches:
Index: Makefile.am
===================================================================
RCS file: Makefile.am
diff -N Makefile.am
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ Makefile.am 3 Jul 2006 02:12:53 -0000 1.1
@@ -0,0 +1,96 @@
+#
+# 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.
+#
+
+include $(top_srcdir)/Makefile.common
+
+SUBDIRS = libecc .
+
+# 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
+
+ourpythondir = $(grpythondir)
+ourlibdir = $(grpythondir)
+
+INCLUDES = $(STD_DEFINES_AND_INCLUDES) $(PYTHON_CPPFLAGS) $(GNURADIO_INCLUDES)
+
+SWIGCPPPYTHONARGS = -fvirtual -python -modern $(PYTHON_CPPFLAGS) \
+ $(GNURADIO_INCLUDES)
+
+ALL_IFILES = \
+ $(LOCAL_IFILES) \
+ $(NON_LOCAL_IFILES)
+
+NON_LOCAL_IFILES = \
+ $(GNURADIO_CORE_INCLUDEDIR)/swig/gnuradio.i
+
+LOCAL_IFILES = \
+ gr_syms_to_metrics.i \
+ gr_decoder_viterbi_block_soft_full.i \
+ gr_streams_encode_convolutional.i \
+ ecc.i
+
+# These files are built by SWIG. The first is the C++ glue.
+# The second is the python wrapper that loads the _howto shared library
+# and knows how to call our extensions.
+
+BUILT_SOURCES = \
+ ecc.cc \
+ ecc.py
+
+# This gets ecc.py installed in the right place
+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_decoder_viterbi_block_soft_full.cc \
+ gr_streams_encode_convolutional.cc \
+ ecc.cc
+
+# magic flags
+_ecc_la_LDFLAGS = $(NO_UNDEFINED) -module -avoid-version
+
+# link the library against the c++ standard library
+_ecc_la_LIBADD = \
+ libecc/libecc.la \
+ $(PYTHON_LDFLAGS) \
+ -lstdc++
+
+ecc.cc ecc.py: ecc.i $(ALL_IFILES)
+ $(SWIG) $(SWIGCPPPYTHONARGS) -module ecc -o ecc.cc $<
+
+# These headers get installed in ${prefix}/include/gnuradio
+grinclude_HEADERS = \
+ gr_syms_to_metrics.h \
+ gr_decoder_viterbi_block_soft_full.h \
+ gr_streams_encode_convolutional.h
+
+# These swig headers get installed in ${prefix}/include/gnuradio/swig
+swiginclude_HEADERS = $(LOCAL_IFILES)
+
+MOSTLYCLEANFILES = $(BUILT_SOURCES) *.pyc *.loT *~
+
+CONFIG_CLEAN_FILES = *.in
Index: __init__.py
===================================================================
RCS file: __init__.py
diff -N __init__.py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ __init__.py 3 Jul 2006 02:12:53 -0000 1.1
@@ -0,0 +1,20 @@
+#
+# 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.
+#
Index: ecc.i
===================================================================
RCS file: ecc.i
diff -N ecc.i
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ ecc.i 3 Jul 2006 02:12:53 -0000 1.1
@@ -0,0 +1,39 @@
+/* -*- 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.
+ */
+
+%feature("autodoc","1");
+%include "exception.i"
+%import "gnuradio.i"
+
+%{
+
+#include "gnuradio_swig_bug_workaround.h" // mandatory bug fix
+#include <gr_streams_encode_convolutional.h>
+#include <gr_decoder_viterbi_block_soft_full.h>
+#include <gr_syms_to_metrics.h>
+#include <stdexcept>
+
+%}
+
+%include "gr_streams_encode_convolutional.i"
+%include "gr_decoder_viterbi_block_soft_full.i"
+%include "gr_syms_to_metrics.i"
Index: gr_decoder_viterbi_block_soft_full.cc
===================================================================
RCS file: gr_decoder_viterbi_block_soft_full.cc
diff -N gr_decoder_viterbi_block_soft_full.cc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_decoder_viterbi_block_soft_full.cc 3 Jul 2006 02:12:53 -0000
1.1
@@ -0,0 +1,1485 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio.
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_dec_blk_conv_soft_full.h>
+#include <gr_io_signature.h>
+#include <assert.h>
+#include <iostream>
+
+const int g_max_frame_size_bits = 10000000;
+const int g_max_num_streams = 10;
+const int g_num_bits_per_byte = 8;
+const int g_max_stream_el_size_bytes = 128;
+
+#define DO_TIME_THOUGHPUT 0
+#define DO_PRINT_DEBUG_INST 0
+#define DO_PRINT_DEBUG_INST_0 0
+#define DO_PRINT_DEBUG_INST_1 0
+#define DO_PRINT_DEBUG_INST_2 0
+#define DO_PRINT_DEBUG_FSM 0
+#define DO_PRINT_DEBUG_INIT 0
+#define DO_PRINT_DEBUG_UP 0
+#define DO_PRINT_DEBUG_UP_0 0
+#define DO_PRINT_DEBUG_UP_1 0
+#define DO_PRINT_DEBUG_MIDDLE 0
+#define DO_PRINT_DEBUG_MIDDLE_0 0
+#define DO_PRINT_DEBUG_MIDDLE_1 0
+#define DO_PRINT_DEBUG_TERM 0
+#define DO_PRINT_DEBUG_TERM_1 0
+#define DO_PRINT_DEBUG_OUTPUT 0
+#define DO_PRINT_DEBUG_OUTPUT_0 0
+#define DO_PRINT_DEBUG_EXIT 0
+#define DO_PRINT_DEBUG 0
+
+#if DO_TIME_THOUGHPUT
+#include <mld/mld_timer.h>
+#endif
+#if DO_PRINT_DEBUG
+#include <mld/n2bs.h>
+#endif
+
+gr_decoder_viterbi_block_soft_full_sptr
+gr_make_dec_blk_conv_soft_full
+(int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination)
+{
+ return gr_decoder_viterbi_block_soft_full_sptr
+ (new gr_decoder_viterbi_block_soft_full (frame_size_bits,
+ num_input_streams,
+ num_output_streams,
+ code_generator,
+ do_termination));
+}
+
+gr_decoder_viterbi_block_soft_full::gr_decoder_viterbi_block_soft_full
+(int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination)
+ : gr_block ("dec_blk_conv_soft_full",
+ gr_make_io_signature (0, 0, 0),
+ gr_make_io_signature (0, 0, 0))
+{
+// make sure the frame length makes sense, #1 - more later
+ if (frame_size_bits > g_max_frame_size_bits) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Requested frame length (" << frame_size_bits <<
+ " bits) must be at most " << g_max_frame_size_bits << " bits.\n";
+ assert (0);
+ }
+
+// check to make sure the number of input streams makes sense
+ if ((n_code_inputs <= 0) | (n_code_inputs > g_max_num_streams)) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Requested number of input streams (" <<
+ n_code_inputs << ") must be between 1 and " <<
+ g_max_num_streams << ".\n";
+ assert (0);
+ }
+
+// check to make sure the number of output streams makes sense
+ if ((n_code_outputs <= 0) | (n_code_outputs > g_max_num_streams)) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Requested number of output streams (" <<
+ n_code_outputs << ") must be between 1 and " <<
+ g_max_num_streams << ".\n";
+ assert (0);
+ }
+
+// make sure the code_generator is the correct length
+ if (code_generators.size () !=
+ ((size_t)(n_code_inputs * n_code_outputs))) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Number of code generator entries (" << code_generators.size () <<
+ ") is not equal to the product of the number of input and output" <<
+ " streams (" << (n_code_inputs * n_code_outputs) << ").\n";
+ assert (0);
+ }
+
+// create the class frame variables
+ d_frame_size_bits = frame_size_bits;
+ d_out_stream_el_size_bytes = out_stream_el_size_bytes;
+ d_n_code_inputs = n_code_inputs;
+ d_n_code_outputs = n_code_outputs;
+ d_do_streaming = (frame_size_bits == 0);
+ d_do_termination = (d_do_streaming == true) ? false : do_termination;
+ d_do_mux_inputs = do_mux_inputs;
+
+// allocate the vectors for doing the encoding. use 32-bit int's
+// actual bits to represent memory and the code, as it makes the
+// operations quite simple the state vectors.
+// code generates are for each I/O combination
+
+ d_code_generators.resize (d_n_code_inputs * d_n_code_outputs, 0);
+
+// check the input code_generator for correctness & find the memory order
+// t_max_mem will be the mamimum number of memories used by the generator
+// t_code_ndx is a counter over all input code_generator elements
+ int t_max_mem = 0, t_code_ndx = d_code_generators.size() - 1;
+// loop over all input streams first, output streams second
+ for (int n = d_n_code_outputs - 1; n >= 0; n--) {
+ int t_all_inputs_zero = 0;
+ for (int m = d_n_code_inputs - 1; m >= 0; m--) {
+ int t_in_code = code_generators[t_code_ndx];
+ t_all_inputs_zero |= t_in_code;
+ int t_code_mem = 0;
+// find the memory requirement for this code generator
+ while (t_in_code != 0) {
+ t_in_code >>= 1;
+ t_code_mem++;
+ }
+ if (t_code_mem > t_max_mem)
+ t_max_mem = t_code_mem;
+// store in d_code_generators in output-first ordering
+ d_code_generators[(m*d_n_code_outputs) + n] =
+ code_generators[t_code_ndx--];
+ }
+ if (t_all_inputs_zero == 0) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "At least 1 generator code for encode-output " << n+1 <<
+ " must be non-0.\n";
+ assert (0);
+ }
+ }
+
+// store the maximum memory order (e.g. "2" -> D^2)
+ d_max_memory = t_max_mem - 1;
+
+// make sure the frame length makes sense, #2
+ if (d_frame_size_bits < d_max_memory) {
+ std::cerr << "gr_decoder_viterbi_block_soft_full: " <<
+ "Requested frame length (" << d_frame_size_bits <<
+ " bit" << (d_frame_size_bits > 1 ? "s" : "") <<
+ ") must be at least 1 memory length (" << d_max_memory <<
+ " bit" << (d_max_memory > 1 ? "s" : "") <<
+ " for this code).\n";
+ assert (0);
+ }
+
+// NOTE: d_n_states is a 'u_long', and thus is quite limited in terms
+// of max memory and # of input streams to 2^32 states
+// This is OK, since that many states would be impossibly slow to decode!
+// might make this a "long long" (64 bits) in the future
+ d_n_states = 1 << (d_max_memory * d_n_code_inputs);
+ d_n_input_combinations = 1 << d_n_code_inputs;
+
+#if DO_PRINT_DEBUG_INST_0
+ std::cout << "Init:\n" <<
+ "d_frame_size_bits = " << d_frame_size_bits << "\n" <<
+ "d_out_stream_el_size_bytes = " << d_out_stream_el_size_bytes << "\n" <<
+ "d_n_code_inputs = " << d_n_code_inputs << "\n" <<
+ "d_n_code_outputs = " << d_n_code_outputs << "\n" <<
+ "d_do_streaming = " <<
+ ((d_do_streaming == true) ? "true" : "false") << "\n" <<
+ "d_do_termination = " <<
+ ((d_do_termination == true) ? "true" : "false") << "\n" <<
+ "d_do_mux_inputs = " <<
+ ((d_do_mux_inputs == true) ? "true" : "false") << "\n" <<
+ "d_max_memory = " << d_max_memory << "\n" <<
+ "d_n_states = " << d_n_states << "\n" <<
+ "d_n_input_combinations = " << d_n_input_combinations << "\n";
+#endif
+
+// leave the output multiple at 1 (element); will save any incomplete
+// output data (int's) in "d_save_buffer"; all input data will be consumed
+
+// create the correct input signature
+ int t_n_input_streams = ((d_do_mux_inputs == true) ?
+ 1 : n_code_outputs);
+
+ set_input_signature (gr_make_io_signature (t_n_input_streams,
+ t_n_input_streams,
+ sizeof (float)));
+// create the correct output signature
+ set_output_signature (gr_make_io_signature (n_code_inputs,
+ n_code_inputs,
+ d_out_stream_el_size_bytes));
+#if DO_PRINT_DEBUG_INST_0
+ std::cout <<
+ "input_signature = [" << t_n_input_streams << ", " <<
+ t_n_input_streams << ", " << sizeof (float) << "]\n" <<
+ "output_signature = [" << n_code_outputs << ", " <<
+ n_code_outputs << ", " << d_out_stream_el_size_bytes << "]\n";
+#endif
+
+// always start the fsm in the "init" state
+ d_fsm = fsm_dec_init;
+
+// create a vector of indexes to states when doing "up" or "termination";
+ d_up_term_states_ndx[0] = new size_t [d_n_states];
+ d_up_term_states_ndx[1] = new size_t [d_n_states];
+
+// create the traceback buffers
+// get the total number of out bits per stream
+ d_n_total_input_bits_per_stream = d_frame_size_bits;
+ if (d_do_termination == true)
+ d_n_total_input_bits_per_stream += d_max_memory;
+ d_n_traceback_els = d_n_total_input_bits_per_stream + 1;
+// create the output buffers:
+// this is a 2d matrix structure, where the first dimension
+// is the number of output bits; the second dimension is
+// the number of states.
+// When doing full frames (no tau), each bit-time's state's traceback
+// contains just the pointer to the previous bit-time's state's traceback
+// as well as the inputs for that connection.
+// No further work is required because each reverse-path is unique
+// once a given end-bit-time's state is determined to be "the one"
+ traceback_t_hdl t_out_buf =
+ d_out_buf = new traceback_t_ptr [d_n_traceback_els];
+ for (size_t n = d_n_traceback_els; n > 0; n--) {
+ (*t_out_buf++) = new traceback_t [d_n_states];
+ }
+
+ // create the save buffers
+ char** t_save_buffer = d_save_buffer = new char* [d_n_code_inputs];
+ size_t t_n_out_bytes = ((d_frame_size_bits / g_num_bits_per_byte) +
+ ((d_frame_size_bits % g_num_bits_per_byte) ? 1 : 0));
+ for (size_t n = 0; n < d_n_code_inputs; n++) {
+ (*t_save_buffer++) = new char [t_n_out_bytes];
+ }
+
+// reset the number of saved bits
+ d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
+
+// setup the internal structures for exiting and entering states
+
+#if DO_PRINT_DEBUG_INST_0
+ std::cout <<
+ "d_n_total in bits / stream = " << d_n_total_input_bits_per_stream << "\n"
<<
+ "d_n_traceback_els = " << d_n_traceback_els << "\n" <<
+ "t_n_out_bytes / stream = " << t_n_out_bytes << "\n";
+#endif
+
+// Find the approximate output rate / input rate
+// each input item produces 1 bit of an output item w/o termination
+ double t_rel_rate = (double)(d_out_stream_el_size_bytes *
g_num_bits_per_byte);
+ if (d_do_termination == true) {
+// include termination bits
+ t_rel_rate *= (((double) d_frame_size_bits) /
+ ((double) d_n_total_input_bits_per_stream));
+ }
+// Set the approximate output rate / input rate
+ set_relative_rate (t_rel_rate);
+
+// 'new' everything first; no connections yet
+ state_t_ptr t_state = d_states[0] = new state_t [d_n_states];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections
+ = new connection_t [d_n_input_combinations];
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ t_connection->d_output_bits = new float [d_n_code_outputs];
+ }
+ }
+
+// 'new' everything first; no connections yet
+ t_state = d_states[1] = new state_t [d_n_states];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections
+ = new connection_t [d_n_input_combinations];
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ t_connection->d_output_bits = new float [d_n_code_outputs];
+ }
+ }
+
+// temporary memory and mask for output bit computations
+ size_t t_memory[d_n_code_inputs];
+ size_t t_memory_mask = ((2 << d_max_memory) - 1) ^ 1;
+
+#if DO_PRINT_DEBUG
+ size_t t_state_print_bits = (d_max_memory * d_n_code_inputs) + 1;
+ size_t t_mem_print_bits = d_max_memory + 2;
+
+ std::cout << "Setting States and Connections\n";
+#endif
+
+// loop over all possible memory states
+ state_t_ptr t_state0 = d_states[0];
+ state_t_ptr t_state1 = d_states[1];
+ for (size_t n = 0; n < d_n_states; n++, t_state0++, t_state1++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "Starting state # " << n << " == " <<
+ n2bs (n, t_state_print_bits) << "\n";
+#endif
+// retrieve the memory values for this state
+// probably a faster way to do this, but since this is
+// executed only upon instantiation, whatever.
+ size_t* t_mem_ptr = t_memory;
+ for (size_t p = 0; p < d_n_code_inputs; p++) {
+ int t_mem = state_get_from (n, p, d_max_memory);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "s_g_f (" <<
+ n2bs (n, t_state_print_bits) << ", " <<
+ p << ", " << d_max_memory << ") => t_m = " <<
+ n2bs (t_mem, t_mem_print_bits) << "\n";
+#endif
+// shift them by 1 (and mask) to make updating for all inputs simple
+ (*t_mem_ptr++) = t_mem << 1;
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "t_m_p[" << p << "] = " <<
+ n2bs (t_mem << 1, t_mem_print_bits) << " == (" <<
+ n2bs (t_mem, t_mem_print_bits) << " << 1)\n";
+#endif
+ }
+
+// loop over all possible input values, 1 bit per input stream
+ connection_t_ptr t_connection0 = t_state0->d_connections;
+ connection_t_ptr t_connection1 = t_state1->d_connections;
+ for (size_t q = 0; q < d_n_input_combinations;
+ q++, t_connection0++, t_connection1++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "Starting inputs " << q << " == " <<
+ n2bs (q, d_n_code_inputs + 1) << "\n";
+#endif
+
+// update memory for this set of inputs
+ t_mem_ptr = t_memory;
+ size_t t_this_input = q;
+
+// loop over all code inputs, and update just the single input bit
+ for (size_t r = d_n_code_inputs; r > 0; r--) {
+ int t_mem = (*t_mem_ptr) & t_memory_mask;
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "t_m = " << n2bs (t_mem, t_mem_print_bits) <<
+ " == " << n2bs (*t_mem_ptr, t_mem_print_bits) <<
+ " & " << n2bs (t_memory_mask, t_mem_print_bits) << "\n";
+#endif
+ (*t_mem_ptr++) = t_mem | (t_this_input & 1);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "t_m_p[" << (d_n_code_inputs - r) << "] = " <<
+ n2bs (t_mem | (t_this_input & 1), t_mem_print_bits) <<
+ " == t_m | " << (t_this_input & 1) << "\n";
+#endif
+ t_this_input >>= 1;
+ }
+
+// got the updated memory for this particular state & inputs
+// recreate the "to" state from the updated memory
+ t_mem_ptr = t_memory;
+ size_t t_out_state = 0;
+ for (size_t p = 0; p < d_n_code_inputs; p++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "s_a_t (" <<
+ n2bs (t_out_state, t_state_print_bits) <<
+ ", " << n2bs (*t_mem_ptr, t_mem_print_bits) << ", " << p <<
+ ", " << d_max_memory << ") ==> t_o_s out = ";
+#endif
+ state_add_to (t_out_state, *t_mem_ptr++, p, d_max_memory);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << n2bs (t_out_state, t_state_print_bits) << "\n";
+#endif
+ }
+
+// get the "to" state pointers from d_states[0] to [1]
+ state_t_ptr t_to_state = &(d_states[1][t_out_state]);
+ t_connection0->d_to = t_to_state;
+ t_connection0->d_to_ndx = t_out_state;
+ float* t_output_bit0 = t_connection0->d_output_bits;
+
+// get the "to" state pointers from d_states[1] to [0]
+ t_to_state = &(d_states[0][t_out_state]);
+ t_connection1->d_to = t_to_state;
+ t_connection1->d_to_ndx = t_out_state;
+ float* t_output_bit1 = t_connection1->d_output_bits;
+
+// determine the ideal output values: loop over all outputs
+ size_t t_vec_ctr = 0;
+ for (size_t s = 0; s < d_n_code_outputs; s++) {
+
+// loop over all inputs, xor'ing the result each time
+ int t_out_result = 0;
+ t_mem_ptr = t_memory;
+ for (size_t t = 0; t < d_n_code_inputs; t++) {
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "b_i = " << n2bs (t_out_result, t_mem_print_bits) <<
+ ", st[" << t << "] = " << n2bs ((*t_mem_ptr), t_mem_print_bits) <<
+ ", cg[" << t_vec_ctr << "] = " <<
+ n2bs (d_code_generators[t_vec_ctr], t_mem_print_bits) <<
+ ", st[] & cg[] = " << n2bs ((*t_mem_ptr) &
+ d_code_generators[t_vec_ctr],
+ t_mem_print_bits);
+#endif
+ t_out_result ^= ((*t_mem_ptr++) &
+ d_code_generators[t_vec_ctr++]);
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << ", b_o = " <<
+ n2bs (t_out_result, t_mem_print_bits) << '\n';
+#endif
+ }
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << "b_r = " << n2bs (t_out_result, t_mem_print_bits);
+#endif
+// sum the number of set bits, mod 2, for the output bit
+ size_t t_out_bit = t_out_result & 1;
+ for (size_t v = d_max_memory; v > 0; v--) {
+ t_out_result >>= 1;
+ t_out_bit ^= (t_out_result & 1);
+ }
+
+// store the result for this particular output stream,
+// converting the bit 1 -> +1.0, and 0 -> -1.0
+ float t_out_value = (float)(((int)(t_out_bit << 1)) - 1);
+ *t_output_bit0++ = t_out_value;
+ *t_output_bit1++ = t_out_value;
+#if DO_PRINT_DEBUG_INST_1
+ std::cout << ", o_v = " << t_out_value << "\n";
+#endif
+
+// finished (for) all output values
+ }
+// finished (for) over all possible input values
+ }
+// finished (for) over all possible states
+ }
+
+// so now d_states is/are completely populated!
+// These make for simple access to looping over all possible inputs or
+// outputs for a given state to determine what the path with the best
+// metric is.
+
+#if DO_PRINT_DEBUG_INST_2
+// loop over all possible memory states
+ std::cout << "State Tables\n";
+ t_state0 = d_states[0];
+ t_state1 = d_states[1];
+ for (size_t n = 0; n < d_n_states; n++, t_state0++, t_state1++) {
+ std::cout << "d_s[0][" << n << "] = " << t_state0 << "\n";
+// loop over all possible input values, 1 bit per input stream
+ connection_t_ptr t_connection0 = t_state0->d_connections;
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection0++) {
+ std::cout << "s0[" << n2bs (n, t_state_print_bits) << "][" <<
+ n2bs (q, d_n_code_inputs+1) << "] = " << t_connection0 <<
+ " -> s1[" << n2bs (t_connection0->d_to_ndx, t_state_print_bits) <<
+ "] = " << t_connection0->d_to << "\n";
+ }
+ std::cout << "d_s[1][" << n << "] = " << t_state1 << "\n";
+ connection_t_ptr t_connection1 = t_state1->d_connections;
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection1++) {
+ std::cout << "s1[" << n2bs (n, t_state_print_bits) << "][" <<
+ n2bs (q, d_n_code_inputs+1) << "] = " << t_connection1 <<
+ " -> s0[" << n2bs (t_connection1->d_to_ndx, t_state_print_bits) <<
+ "] = " << t_connection1->d_to << "\n";
+ }
+ }
+
+ traceback_t_hdl t_out_bufs = d_out_buf;
+ for (size_t n = 0; n < d_n_traceback_els; n++, *t_out_bufs++) {
+ traceback_t_ptr t_out_buf = *t_out_bufs;
+ for (size_t m = 0; m < d_n_states; m++, t_out_buf++) {
+ std::cout << "tb[" << n << "] = " << t_out_bufs <<
+ ", &tb[" << n << "][" << m << "] = " << (&d_out_buf[n][m]) <<
+ ", tb[" << n << "," << m << "] = " << t_out_buf << "\n";
+ }
+ }
+
+ std::cout << "Done with instantiation.\n";
+#endif
+}
+
+gr_decoder_viterbi_block_soft_full::~gr_decoder_viterbi_block_soft_full
+()
+{
+// reverse over from allocation
+
+ delete [] d_up_term_states_ndx[0];
+ delete [] d_up_term_states_ndx[1];
+
+// delete the state's structures
+ state_t_ptr t_state = d_states[0];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections;
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ delete [] t_connection->d_output_bits;
+ }
+ delete [] t_state->d_connections;
+ }
+ delete [] d_states[0];
+
+ t_state = d_states[1];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ connection_t_ptr t_connection = t_state->d_connections;
+ for (size_t m = d_n_input_combinations; m > 0; m--, t_connection++) {
+ delete [] t_connection->d_output_bits;
+ }
+ delete [] t_state->d_connections;
+ }
+ delete [] d_states[1];
+
+// delete the save buffer
+ char** t_save_buffer = d_save_buffer;
+ for (size_t n = 0; n < d_n_code_inputs; n++) {
+ delete [] (*t_save_buffer++);
+ }
+ delete [] d_save_buffer;
+
+// delete the output buffer
+ traceback_t_hdl t_out_buf = d_out_buf;
+ for (size_t n = d_n_traceback_els; n > 0; n--) {
+ delete [] (*t_out_buf++);
+ }
+ delete [] d_out_buf;
+}
+
+void gr_decoder_viterbi_block_soft_full::reset_metrics (u_char which)
+{
+ state_t_ptr t_state = d_states[which&1];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ t_state->d_max_metric = -1e10;
+#if 0
+// probably don't need to do these, try removing them later
+ t_state->d_max_state_ndx = 0;
+ t_state->d_max_input = -1;
+#endif
+ }
+}
+
+void gr_decoder_viterbi_block_soft_full::zero_metrics (u_char which)
+{
+ state_t_ptr t_state = d_states[which&1];
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+ t_state->d_max_metric = 0;
+#if 0
+// probably don't need to do these, try removing them later
+ t_state->d_max_state_ndx = -1;
+ t_state->d_max_input = -1;
+#endif
+ }
+}
+
+void gr_decoder_viterbi_block_soft_full::forecast
+(int noutput_items,
+ gr_vector_int &ninput_items_required)
+{
+ int ninput_items = fixed_rate_noutput_to_ninput (noutput_items);
+
+ int ninputs = ninput_items_required.size();
+ for (int n = 0; n < ninputs; n++)
+ ninput_items_required[n] = ninput_items;
+}
+
+/*
+ * Compute the number of input items (soft symbols [floats]) needed to produce
+ * 'noutput' items (elements). For convolutional decoders, there is 1
+ * bit output per bit input per stream, with the addition of a some
+ * bits for trellis termination if selected. Without termination,
+ * there is exactly 1:1 input to output (1 symbol in to 1 bit out),
+ * no matter the encoding type.
+ *
+ * if (not terminating), then get the number of output bytes.
+ *
+ * otherwise, find the number of frames (not necessarily and integer),
+ * and then compute the number of input bits (including termination)
+ * required to produce those frames. Subtract the number of bits
+ * leftover from the previous computation, then find the number of input
+ * elements (soft symbols), ceil'd to make sure there are enough.
+ *
+ * finally, if the input streams are mux'ed, then multiply by the
+ * number of inputs.
+ */
+
+int
+gr_decoder_viterbi_block_soft_full::fixed_rate_noutput_to_ninput
+(int noutput_items)
+{
+ int t_ninput_items = 0;
+ int t_noutput_bits = (noutput_items * d_out_stream_el_size_bytes *
+ g_num_bits_per_byte) - d_n_saved_bits;
+// if there are enough saved bits, just use those, no inputs required
+ if (t_noutput_bits <= 0)
+ return (t_ninput_items);
+
+// remove any bits already in the decoding trellis
+ if (d_time_count != 0) {
+ int t_time_bits = ((d_time_count > d_frame_size_bits) ? 0 :
+ d_frame_size_bits - d_time_count);
+ t_noutput_bits -= t_time_bits;
+ t_ninput_items += t_time_bits;
+ }
+// if completing this trellis doesn't create enough outputs ...
+ if (t_noutput_bits > 0) {
+
+// there is a 1:1 ratio between input symbols and output bits (per
+// stream), except for termination bits which are already taken into
+// account in the total # of input bits per stream class variable;
+// need to round the # output bits to the
+
+// find the number of frames, ceil'd to the next higher integer
+ int t_nframes = (int) ceilf (((float) t_noutput_bits) /
+ ((float) d_frame_size_bits));
+// find the number of required input bits
+ t_ninput_items += t_nframes * d_n_total_input_bits_per_stream;
+ }
+
+// if doing mux'ing, there are more elements in the single input
+ if (d_do_mux_inputs == true) {
+ t_ninput_items *= d_n_code_outputs;
+ }
+ return (t_ninput_items);
+}
+
+int
+gr_decoder_viterbi_block_soft_full::general_work
+(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+#if DO_TIME_THOUGHPUT
+ struct timeval t_tp;
+ start_timer (&t_tp);
+#endif
+#if DO_PRINT_DEBUG
+ size_t t_state_print_bits = (d_max_memory * d_n_code_inputs) + 1;
+ size_t t_mem_print_bits = d_max_memory + 2;
+#endif
+// setup variables for quicker access
+ const float **in_buf = (const float **) &input_items[0];
+ char **out_buf = (char **) &output_items[0];
+ int t_in_buf_ndx = 0, t_out_buf_ndx = 0;
+ int t_out_bit_shift = 0;
+ int t_ninput_items = fixed_rate_noutput_to_ninput (noutput_items);
+ int t_noutput_bytes = noutput_items * d_out_stream_el_size_bytes;
+
+#if DO_PRINT_DEBUG_INST
+ std::cout << "# output items = " << noutput_items << " (" <<
+ t_noutput_bytes << " Bytes, " << (t_noutput_bytes * g_num_bits_per_byte) <<
+ " bits), # input items = " << t_ninput_items << " Symbols\n";
+ for (size_t n = 0; n < ninput_items.size(); n++) {
+ std::cout << "# input items [" << n << "] = " << ninput_items[n] << "\n";
+ }
+#endif
+
+// put any leftover bits into the output
+ if (d_n_saved_bits != 0) {
+// copy the leftover from the save buffer
+// check to make sure it will all fit
+ size_t t_noutput_bits = t_noutput_bytes * g_num_bits_per_byte;
+ size_t t_n_copy;
+ if (t_noutput_bits < d_n_saved_bits) {
+// asking for fewer bits than available; set to copy
+// just what's being asked for
+ t_n_copy = t_noutput_bytes;
+ } else {
+// asking for at least as many bits as available; set to copy all
+ t_out_buf_ndx = d_n_saved_bits / g_num_bits_per_byte;
+ t_out_bit_shift = d_n_saved_bits % g_num_bits_per_byte;
+ t_n_copy = t_out_buf_ndx + (t_out_bit_shift != 0 ? 1 : 0);
+ }
+// do the copy for all output streams (code inputs)
+// copy starting at save buffer index "start"
+ for (size_t n = 0; n < d_n_code_inputs; n++)
+ bcopy (&(d_save_buffer[n][d_n_saved_bits_start_ndx]),
+ out_buf[n], t_n_copy);
+#if DO_PRINT_DEBUG_INST
+ std::cout << "Copied " << t_n_copy << " Byte" <<
+ (t_n_copy != 1 ? "s" : "") << ": s_b[][" <<
+ d_n_saved_bits_start_ndx << "] => o_b[][0]\n" <<
+ "# saved bits = " << d_n_saved_bits <<
+ ", o_b_ndx = " << t_out_buf_ndx <<
+ ", bit shift = " << t_out_bit_shift << "\n";
+#endif
+// update the number of saved bits and start
+ if (t_noutput_bits < d_n_saved_bits) {
+// asking for fewer bit than available: update
+// the number of saved bits and their starting index
+ d_n_saved_bits_start_ndx += t_noutput_bytes;
+ d_n_saved_bits -= (t_noutput_bytes * g_num_bits_per_byte);
+#if DO_PRINT_DEBUG_INST
+ std::cout << "Updated # saved bits = " << d_n_saved_bits <<
+ ", index = " << d_n_saved_bits_start_ndx << "\n";
+#endif
+// nothing to consume; return the desired number of output items
+ return (noutput_items);
+ } else {
+ d_n_saved_bits_start_ndx = d_n_saved_bits = 0;
+ }
+ }
+#if DO_PRINT_DEBUG_INST
+ std::cout << "Starting FSM in state: " <<
+ (d_fsm == fsm_dec_init ? "init" :
+ (d_fsm == fsm_dec_doing_up ? "up" :
+ (d_fsm == fsm_dec_doing_middle ? "middle" :
+ (d_fsm == fsm_dec_doing_term ? "term" :
+ (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "\n";
+#endif
+
+// while there are input items to create
+ while (t_out_buf_ndx < t_noutput_bytes) {
+#if DO_PRINT_DEBUG_FMS
+ std::cout << "Starting 'while': processing " << t_in_buf_ndx << " of " <<
+ t_ninput_items << " items.\nJumping to state '" <<
+ (d_fsm == fsm_dec_init ? "init" :
+ (d_fsm == fsm_dec_doing_up ? "up" :
+ (d_fsm == fsm_dec_doing_middle ? "middle" :
+ (d_fsm == fsm_dec_doing_term ? "term" :
+ (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "'\n";
+#endif
+// jump to the correct state in the fsm
+ switch (d_fsm) {
+ case fsm_dec_doing_up:
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Starting fsm_dec_doing_up\n";
+#endif
+// set the number of up_down indices
+ size_t t_n_up_down_ndx = 1 << (d_n_code_inputs *
+ d_time_count);
+// stay in this state until the correct number of input symbols are
+// reached; exit also if we run out of input symbols to process
+ while ((d_time_count < d_max_memory) &
+ (t_in_buf_ndx < t_ninput_items)) {
+#if DO_PRINT_DEBUG_UP_0
+ std::cout << "Doing 'while' loop:\n" <<
+ "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" <<
+ "d_time_count = " << d_time_count << "\n" <<
+ "d_max_memory = " << d_max_memory << "\n" <<
+ "t_in_buf_ndx = " << t_in_buf_ndx << "\n" <<
+ "t_ninput_items = " << t_ninput_items << "\n";
+#endif
+// use the "from" states, loop over all inputs and compute the metric for
+// each & store it in the "to" state at the end of the connection.
+// no need to compare metrics yet, since none join into any given state
+
+#if 0
+// reset the "to" state's metrics
+// probably don't need to do this; try removing later
+ reset_metrics (d_states_ndx ^ 1);
+#if DO_PRINT_DEBUG_UP
+ std::cout << "Reset Metrics\n";
+#endif
+#endif
+
+// reset the state's index for each set of new inputs
+ size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+ size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
+// loop over all current stored "up" states
+ for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+ size_t t_state_ndx = *t_state_ndx_ptr++;
+// get a pointer to this state's structure
+ state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// get the connections for all inputs
+ connection_t_ptr t_connection = t_state->d_connections;
+#if DO_PRINT_DEBUG_UP_0
+ std::cout << "Looping over all 'up' states:\n" <<
+ "n = " << n << "\n" <<
+ "t_n_up_down_ndx = " << t_n_up_down_ndx << "\n" <<
+ "d_states_ndx = " << d_states_ndx << "\n" <<
+ "t_state_ndx = " << t_state_ndx << "\n" <<
+ "d_n_input_combs = " << d_n_input_combinations << "\n" <<
+ "t_state = " << t_state << "\n" <<
+ "t_connection = " << t_connection << "\n";
+#endif
+// loop over all possible input values, 1 bit per input stream
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
+// find the "to" state for this connection
+ state_t_ptr t_to_state = t_connection->d_to;
+// get the output bits for this connection
+ float* t_output_bit = t_connection->d_output_bits;
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+#if DO_PRINT_DEBUG_UP_0
+ std::cout <<
+ "to state index = " << t_connection->d_to_ndx << "\n" <<
+ "current metric = " << t_metric << "\n";
+#endif
+ if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+ const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+ for (size_t r = d_n_code_outputs; r > 0; r--) {
+#if DO_PRINT_DEBUG_UP
+ std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
+ *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += ((*t_in_buf++) * (*t_output_bit++));
+#if DO_PRINT_DEBUG_UP
+ std::cout << t_metric << "\n";
+#endif
+ }
+ } else {
+// loop over all encoder-output values
+ for (size_t r = 0; r < d_n_code_outputs; r++) {
+#if DO_PRINT_DEBUG_UP
+ std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
+ ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+#if DO_PRINT_DEBUG_UP
+ std::cout << t_metric << "\n";
+#endif
+ }
+ }
+// get the "to" state index
+ size_t t_to_ndx = t_connection->d_to_ndx;
+// store the metric in the "to" state; should not have been used before
+ t_to_state->d_max_metric = t_metric;
+// add the "to" state index to the "up" state list
+ *t_next_state_ndx_ptr++ = t_to_ndx;
+// update the traceback structure, depending on which variety it is
+// doing full trellis before decoding; use d_out_buf
+// simple: get the current state & output state
+ traceback_t_ptr t_out_buf = &(d_out_buf[d_time_count]
+ [t_state_ndx]);
+ traceback_t_ptr t_next_out_buf = &(d_out_buf[d_time_count+1]
+ [t_to_ndx]);
+#if DO_PRINT_DEBUG_UP_1
+ std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n" <<
+ "ndx[" << n << "] == " << t_state_ndx <<
+ ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+ "]: max_ndx = " <<
+ n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+ ", input = " << n2bs(q, d_n_code_inputs+1) <<
+ ": " << t_next_out_buf << " => " << t_out_buf << "\n";
+#endif
+// and connect output to the current, set inputs on output
+ t_next_out_buf->d_prev = t_out_buf;
+ t_next_out_buf->d_inputs = q;
+// finished (for) this input value
+ }
+// finished (for) this "up_term" state
+ }
+// increment the in_buf index, depending on mux'ing or not
+ t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counter
+ d_time_count++;
+// update the number of "up_term" states
+ d_up_term_ndx ^= 1;
+// increase the number of using states
+ t_n_up_down_ndx <<= d_n_code_inputs;
+// change which d_states' index to use as starting
+ d_states_ndx ^= 1;
+// finished (while) staying in this fsm state or not
+ }
+// if reached the end of doing the "up" part of the trellis,
+// switch states into the middle
+ if (d_time_count == d_max_memory) {
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Setting FSM to fsm_dec_doing_middle\n";
+#endif
+ d_fsm = fsm_dec_doing_middle;
+ }
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_doing_up\n";
+#endif
+ break;
+ case (fsm_dec_doing_middle):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_doing_middle\n";
+#endif
+// stay in this state until the correct number of input symbols is
+// reached (if doing block coding), or until there are no more input
+// symbols to parse
+ while (((d_frame_size_bits != 0) &
+ (d_time_count < d_frame_size_bits) &
+ (t_in_buf_ndx < t_ninput_items)) |
+ ((d_frame_size_bits == 0) &
+ (t_in_buf_ndx < t_ninput_items))) {
+// use all states, loop over all inputs, compute the metric for
+// each; compare the current metric with all previous stored metric in the
+// endpoint of the connection to find the highest one.
+
+// reset the "to" state's metrics
+ reset_metrics (d_states_ndx ^ 1);
+// get the state's index for each set of new inputs
+ state_t_ptr t_state = d_states[d_states_ndx];
+#if DO_PRINT_DEBUG_MIDDLE
+ std::cout << "Time Count " << (d_time_count+1) << " of " <<
+ d_frame_size_bits << "\n" <<
+ "d_states_ndx = " << d_states_ndx << "\n";;
+#endif
+// loop over all current states
+ for (size_t n = 0; n < d_n_states; n++, t_state++) {
+// loop over all possible input values, 1 bit per input stream
+ connection_t_ptr t_connection = t_state->d_connections;
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "Looping over all 'middle' states: " <<
+ n << " of " << d_n_states << "\n";
+#endif
+ for (size_t q = 0; q < d_n_input_combinations; q++, t_connection++) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "Input = " << n2bs(q, d_n_code_inputs+1) << "\n";
+#endif
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+// get the "to" state
+ state_t_ptr t_to_state = t_connection->d_to;
+// get that state's metric
+ float t_to_metric = t_to_state->d_max_metric;
+// see if the computation is even needed;
+// maximum change is d_n_code_outputs if all bits match exactly
+ if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "!not computing metric!\n";
+#endif
+ continue;
+ }
+// metrics are close enough; do the computation and the compare
+// get the output bits for this connection
+ float* t_output_bit = t_connection->d_output_bits;
+ if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+ const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+ for (size_t r = d_n_code_outputs; r > 0; r--) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "in_sym = " << *t_in_buf << ", code_out_bit = " <<
+ *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += ((*t_in_buf++) * (*t_output_bit++));
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << t_metric << "\n";
+#endif
+ }
+ } else {
+// loop over all encoder-output values
+ for (size_t r = 0; r < d_n_code_outputs; r++) {
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << "in_sym = " << in_buf[r][t_in_buf_ndx] <<
+ ", code_out_bit = " << *t_output_bit << " ==> metric -> ";
+#endif
+ t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+#if DO_PRINT_DEBUG_MIDDLE_0
+ std::cout << t_metric << "\n";
+#endif
+ }
+ }
+// done with this input value; compare old and new metrics
+ if (t_metric > t_to_metric) {
+#if DO_PRINT_DEBUG_MIDDLE
+ std::cout << "New Metric to s[" <<
+ n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
+ if (t_to_state->d_max_metric == -1e10) {
+ std::cout << "setting to ";
+ } else {
+ std::cout << "was s[" <<
+ n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
+ "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
+ "]@ " << t_to_state->d_max_metric << " now ";
+ }
+ std::cout << "s[" << n2bs(n,t_state_print_bits) << "] i[" <<
+ n2bs (q, d_n_code_inputs+1) << "]@ " << t_metric << "\n";
+#endif
+// new metric is better; copy that info into the "to" state
+ t_to_state->d_max_metric = t_metric;
+ t_to_state->d_max_state_ndx = n;
+ t_to_state->d_max_input = q;
+ }
+// finished (for) this input value
+ }
+// finished (for) this state
+ }
+// done with all states and all inputs; now update the traceback structure
+// change which d_states' index to use as starting
+ d_states_ndx ^= 1;
+// get the state's index for the "to" set of new inputs to get the
+// "max" stuff from
+ t_state = d_states[d_states_ndx];
+// update the traceback structure
+// loop over all current states
+ traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
+ traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
+#if DO_PRINT_DEBUG_MIDDLE_1
+ std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
+#endif
+ for (size_t n = d_n_states; n > 0; n--, t_state++) {
+// simple: get the current state & output state
+// and connect output to the current, set inputs on output
+ traceback_t_ptr t_out_buf = t_out_bufs++;
+ traceback_t_ptr t_prev_out_buf =
+ &(t_prev_out_bufs[t_state->d_max_state_ndx]);
+#if DO_PRINT_DEBUG_MIDDLE_1
+ std::cout << "s[" << n2bs(d_n_states-n,t_state_print_bits) <<
+ "]: max_ndx = " <<
+ n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+ ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
+ ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
+#endif
+ t_out_buf->d_prev = t_prev_out_buf;
+ t_out_buf->d_inputs = t_state->d_max_input;
+// finished doing this state
+ }
+// increment the in_buf index, depending on mux'ing or not
+ t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counter
+ d_time_count++;
+// finished (while) staying in this fsm state or not
+ }
+ if ((d_frame_size_bits != 0) &
+ (d_time_count == d_frame_size_bits)) {
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Setting FSM to fsm_dec_doing_term\n";
+#endif
+ d_fsm = fsm_dec_doing_term;
+ }
+ break;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_doing_middle\n";
+#endif
+ case (fsm_dec_doing_term):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_doing_term\n";
+#endif
+// set the "next" up_down index to the end of their states
+ size_t t_time_count = d_max_memory - (d_time_count - d_frame_size_bits);
+ t_n_up_down_ndx = 1 << (d_n_code_inputs * t_time_count);
+// stay in this state until the correct number of input symbols are
+// reached; exit also if we run out of input symbols to process
+ while ((t_time_count > 0) &
+ (t_in_buf_ndx < t_ninput_items)) {
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "Doing time " << (d_max_memory - t_time_count + 1) <<
+ " of " << d_max_memory << "; starting buf[" << t_in_buf_ndx <<
+ "] of [" << t_ninput_items << "]\n";
+#endif
+// use the "to" states,
+// FIXME: loop over just the "0" inputs
+// and compute the metric for
+// each, compare & store it in the "to" state at the end of the connection.
+
+// reset the "to" state's metrics
+ reset_metrics (d_states_ndx ^ 1);
+// reset the state's index for each set of new inputs
+ size_t* t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+ size_t* t_next_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx ^ 1];
+// loop over all current stored "term" state indeces
+ for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+ size_t t_state_ndx = *t_state_ndx_ptr++;
+ state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// loop over just the all 0 input value (d_connections[0])
+ connection_t_ptr t_connection = t_state->d_connections;
+// get the "to" state
+ state_t_ptr t_to_state = t_connection->d_to;
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+// get that state's metric
+ float t_to_metric = t_to_state->d_max_metric;
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "Term state " << (n+1) << " of " << t_n_up_down_ndx <<
+ "; using d_s[" << d_states_ndx << "][" <<
+ n2bs(t_state_ndx,t_state_print_bits) << "]\n";
+#endif
+// see if the computation is even needed;
+// maximum change is d_n_code_outputs if all bits match exactly
+ if ((t_to_metric - t_metric) > ((float) 2*d_n_code_outputs)) {
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "!not computing metric!\n";
+#endif
+ continue;
+ }
+// metrics are close enough; do the computation and the compare
+// get the output bits for this connection
+ float* t_output_bit = t_connection->d_output_bits;
+ if (d_do_mux_inputs == true) {
+// if using mux'ed input streams, handle differently
+ const float* t_in_buf = &(in_buf[0][t_in_buf_ndx]);
+// loop over all encoder-output values
+ for (size_t r = d_n_code_outputs; r > 0; r--) {
+ t_metric += ((*t_in_buf++) * (*t_output_bit++));
+ }
+ } else {
+// loop over all encoder-output values
+ for (size_t r = 0; r < d_n_code_outputs; r++) {
+ t_metric += (in_buf[r][t_in_buf_ndx] * (*t_output_bit++));
+ }
+ }
+// done with this input value; compare old and new metrics
+// see if it's the best metric
+ if (t_metric > t_to_metric) {
+#if DO_PRINT_DEBUG_TERM
+ std::cout << "New Metric to s[" <<
+ n2bs (t_connection->d_to_ndx,t_state_print_bits) << "]: ";
+ if (t_to_state->d_max_metric == -1e10) {
+ std::cout << "setting to ";
+ } else {
+ std::cout << "was s[" <<
+ n2bs(t_to_state->d_max_state_ndx,t_state_print_bits) <<
+ "]i[" << n2bs (t_to_state->d_max_input, d_n_code_inputs+1) <<
+ "]@ " << t_to_state->d_max_metric << " now ";
+ }
+ std::cout << "s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+ "] i[" << n2bs (0, d_n_code_inputs+1) << "]@ " << t_metric <<
"\n";
+#endif
+ t_to_state->d_max_metric = t_metric;
+ t_to_state->d_max_state_ndx = t_state_ndx;
+ t_to_state->d_max_input = 0;
+ }
+// add the "to" state's index to the "next" set of state's indices list
+ *t_next_state_ndx_ptr++ = t_connection->d_to_ndx;
+// finished (for) this state
+ }
+// done with all states and all inputs; now update the traceback structure
+// change which d_states' index to use as starting
+ d_states_ndx ^= 1;
+// update the number of "up_term" states
+ d_up_term_ndx ^= 1;
+// reduce the number of using states
+ t_n_up_down_ndx >>= d_n_code_inputs;
+// reset the state's index for each set of new inputs
+ t_state_ndx_ptr = d_up_term_states_ndx[d_up_term_ndx];
+// update the traceback structure
+// loop over all current states
+ traceback_t_ptr t_prev_out_bufs = d_out_buf[d_time_count];
+ traceback_t_ptr t_out_bufs = d_out_buf[d_time_count+1];
+#if DO_PRINT_DEBUG_TERM_1
+ std::cout << "d_o_b[" << d_time_count+1 << "] => d_o_b prev\n";
+#endif
+// loop over all current stored "term" state indices
+ for (size_t n = 0; n < t_n_up_down_ndx; n++) {
+// get the start index and then pointer to each of the "to" states,
+// which hold the newest "max" stuff
+ size_t t_state_ndx = *t_state_ndx_ptr++;
+ state_t_ptr t_state = &(d_states[d_states_ndx][t_state_ndx]);
+// simple: get the current state & output state
+// and connect output to the current, set inputs on output
+ traceback_t_ptr t_out_buf = &(t_out_bufs[t_state_ndx]);
+ traceback_t_ptr t_prev_out_buf =
+ &(t_prev_out_bufs[t_state->d_max_state_ndx]);
+#if DO_PRINT_DEBUG_TERM_1
+ std::cout << "ndx[" << n << "] == " << t_state_ndx <<
+ ", s[" << n2bs(t_state_ndx,t_state_print_bits) <<
+ "]: max_ndx = " <<
+ n2bs(t_state->d_max_state_ndx,t_state_print_bits) <<
+ ", input = " << n2bs(t_state->d_max_input, d_n_code_inputs+1) <<
+ ": " << t_out_buf << " => " << t_prev_out_buf << "\n";
+#endif
+ t_out_buf->d_prev = t_prev_out_buf;
+ t_out_buf->d_inputs = t_state->d_max_input;
+// finished (for) this state
+ }
+// increment the in_buf index, depending on mux'ing or not
+ t_in_buf_ndx += (d_do_mux_inputs == false) ? 1 : d_n_code_outputs;
+// increment the time counters
+ t_time_count--;
+ d_time_count++;
+// finished (while) staying in this fsm state or not
+ }
+ if (t_time_count == 0) {
+// finished this trellis, now move as much of the decoded input to the
+// output buffer as possible
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Setting FSM to fsm_dec_output\n";
+#endif
+ d_fsm = fsm_dec_output;
+ }
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_doing_term\n";
+#endif
+ break;
+ case (fsm_dec_output):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_output.\n";
+#endif
+// this is done in reverse bit order (last time to first time)
+// using the traceback structure in d_out_buf, starting with
+// the maximum valued one in the last time slot, then using
+// the traceback's "d_prev" link to trace the trellis back
+
+// see where the output data will terminate
+ int t_next_out_buf_ndx = (t_out_buf_ndx +
+ (d_frame_size_bits / g_num_bits_per_byte));
+ int t_next_out_bit_shift = (t_out_bit_shift +
+ (d_frame_size_bits % g_num_bits_per_byte));
+ if (t_next_out_bit_shift >= g_num_bits_per_byte) {
+ t_next_out_bit_shift -= g_num_bits_per_byte;
+ t_next_out_buf_ndx++;
+ }
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "First bit in at out[][" << t_out_buf_ndx << "].[" <<
+ t_out_bit_shift << "] -> " << d_frame_size_bits << " bits == " <<
+ (d_frame_size_bits / g_num_bits_per_byte) << " Byte" <<
+ ((d_frame_size_bits / g_num_bits_per_byte) != 1 ? "s" : "") <<
+ " + " << (d_frame_size_bits % g_num_bits_per_byte) << " bit" <<
+ ((d_frame_size_bits % g_num_bits_per_byte) != 1 ? "s" : "") <<
+ "\nNext set of bits start at out[][" << t_next_out_buf_ndx <<
+ "].[" << t_next_out_bit_shift << "]\n";
+#endif
+// find the starting traceback structure
+ traceback_t_ptr t_out_buf;
+ if (d_do_termination == true) {
+// FIXME: assume termination state == 0
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Using termination; going through trellis for " <<
+ d_max_memory << " bit" <<
+ ((d_max_memory != 1) ? "s" : "") << "\n";
+#endif
+ t_out_buf = &(d_out_buf[d_time_count][0]);
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Starting traceback ptr " << t_out_buf << "\n";
+#endif
+// skip over the termination bits
+ for (size_t n = d_max_memory; n > 0; n--) {
+ t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+ }
+ } else {
+// no termination but doing block coding;
+// FIXME: use the state with the bext metric
+// get the state's index for each set of new inputs
+ state_t_ptr t_state = d_states[d_states_ndx];
+ float t_max_metric = t_state->d_max_metric;
+ size_t t_max_state_ndx = 0;
+ t_state++;
+// loop over all current states
+ for (size_t n = 1; n < d_n_states; n++, t_state++) {
+// start with this state's metric
+ float t_metric = t_state->d_max_metric;
+// compare with current max
+ if (t_metric > t_max_metric) {
+ t_max_metric = t_metric;
+ t_max_state_ndx = n;
+ }
+ }
+// get the correct out_buf reference to start with
+ t_out_buf = &(d_out_buf[d_time_count][t_max_state_ndx]);
+ }
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "Found starting traceback ptr " << t_out_buf <<
+ "; getting all " << d_frame_size_bits << " bits per stream.\n";
+#endif
+// now we've got the starting traceback structure address;
+// check to make sure there is enough space in each output buffer
+ size_t t_frame_bit_ndx = d_frame_size_bits;
+ if ((t_next_out_buf_ndx > t_noutput_bytes) |
+ ((t_next_out_buf_ndx == t_noutput_bytes) &
+ (t_next_out_bit_shift != 0))) {
+// not enough space for all output bits;
+// find the number of extra bits to save
+ size_t t_save_buf_ndx = t_next_out_buf_ndx - t_noutput_bytes;
+ size_t t_n_extra_bits = ((t_save_buf_ndx * g_num_bits_per_byte) +
+ t_next_out_bit_shift);
+// set the number of saved bits
+ d_n_saved_bits = t_n_extra_bits;
+// remove the extra bits from the number to copy to the output buffer
+ t_frame_bit_ndx -= t_n_extra_bits;
+// find the actual output buf index, once we get there
+ t_next_out_buf_ndx -= t_save_buf_ndx;
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "Not enough output buffer space:\n" <<
+ "len (o_b) = " << t_noutput_bytes << " ==> " <<
+ t_n_extra_bits << " extra bit" <<
+ (t_n_extra_bits != 1 ? "s" : "") << " == " <<
+ t_save_buf_ndx << " Byte" <<
+ (t_save_buf_ndx != 1 ? "s" : "") << ", " <<
+ t_next_out_bit_shift << " bit" <<
+ (t_next_out_bit_shift != 1 ? "s" : "") << "\n";
+#endif
+// zero each output buffers' bytes
+ size_t t_n_zero = t_save_buf_ndx + (t_next_out_bit_shift ? 1 : 0);
+#if DO_PRINT_DEBUG_OUTPUT
+ size_t t_n_out_bytes = ((d_frame_size_bits / g_num_bits_per_byte) +
+ ((d_frame_size_bits % g_num_bits_per_byte) ? 1
: 0));
+ std::cout << "Zeroing save buffer from for " << t_n_zero <<
+ " Byte" << (t_n_zero != 1 ? "s" : "") << " (of " <<
+ d_frame_size_bits << " bit" <<
+ (d_frame_size_bits != 1 ? "s" : "") << " == " << t_n_out_bytes <<
+ " Byte" << (t_n_out_bytes != 1 ? "s" : "") << ")\n";
+#endif
+ for (size_t m = 0; m < d_n_code_inputs; m++)
+ bzero (d_save_buffer[m], t_n_zero);
+// loop over all extra bits
+ for (size_t n = t_n_extra_bits; n > 0; n--) {
+// first decrement the output bit & byte as necessary
+ if (--t_next_out_bit_shift < 0) {
+ t_next_out_bit_shift += g_num_bits_per_byte;
+ t_save_buf_ndx--;
+ }
+// get the encoder inputs to output
+ size_t t_inputs = t_out_buf->d_inputs;
+// loop over all code inputs (decoder-outputs), 1 bit per stream
+ for (size_t m = 0; m < d_n_code_inputs; m++) {
+ d_save_buffer[m][t_save_buf_ndx] |=
+ ((t_inputs & 1) << t_next_out_bit_shift);
+ t_inputs >>= 1;
+ }
+ t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+ }
+// at exit, "t_out_buf_ndx" should be == t_noutput_bytes, and
+// "t_out_bit_shift" should be 0; check these!
+#if DO_PRINT_DEBUG_OUTPUT
+ std::cout << "n_o_b_ndx (" << t_next_out_buf_ndx << ") ?=? " <<
+ "#o_B (" << t_noutput_bytes << ") & t_o_b_sh (" <<
+ t_next_out_bit_shift << ") ?=? 0\n";
+ assert (t_next_out_buf_ndx == t_noutput_bytes);
+ assert (t_next_out_bit_shift == 0);
+#endif
+ }
+// set the correct output buffer index and bit shift
+ t_out_bit_shift = t_next_out_bit_shift;
+ t_out_buf_ndx = t_next_out_buf_ndx;
+// copy any remaining bits looping backwards in bit-time
+// through the traceback trellis
+ for (size_t n = t_frame_bit_ndx; n > 0; n--) {
+// first decrement the output bit & byte as necessary
+ if (--t_out_bit_shift < 0) {
+ t_out_bit_shift += g_num_bits_per_byte;
+ t_out_buf_ndx--;
+ }
+// get the encoder inputs to output
+ size_t t_inputs = t_out_buf->d_inputs;
+// loop over all code inputs (decoder-outputs), 1 bit per stream
+ for (size_t m = 0; m < d_n_code_inputs; m++) {
+ out_buf[m][t_out_buf_ndx] |= ((t_inputs & 1) << t_out_bit_shift);
+ t_inputs >>= 1;
+ }
+ t_out_buf = t_out_buf->d_prev;
+#if DO_PRINT_DEBUG_OUTPUT_0
+ std::cout << "Next traceback ptr " << t_out_buf << "\n";
+#endif
+ }
+// set the next output byte and bit-shift
+ t_out_bit_shift = t_next_out_bit_shift;
+ t_out_buf_ndx = t_next_out_buf_ndx;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Set FSM to fsm_dec_init\n";
+#endif
+ d_fsm = fsm_dec_init;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_output\n";
+#endif
+ break;
+ case (fsm_dec_init):
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Entered fsm_dec_init\n";
+#endif
+// this is called immediately (first input bit upon startup),
+// or after termination of a trellis.
+
+// reset states to the 0'th one
+ d_up_term_ndx = d_states_ndx = 0;
+// zero the metrics for those states
+ zero_metrics (0);
+#if 0
+// might not need to do this; check and see after it works
+// reset up_term states and number so that there is 1 item, the "0" state.
+ bzero (d_up_term_states_ndx[0], sizeof (size_t) * d_n_states);
+ bzero (d_up_term_states_ndx[1], sizeof (size_t) * d_n_states);
+#else
+ d_up_term_states_ndx[0][0] = 0;
+#endif
+// reset time count back to the start
+ d_time_count = 0;
+#if 0
+// reset the traceback structures
+// might not need to do this; check and see after it works
+ traceback_t_hdl t_out_bufs = d_out_buf;
+ for (size_t n = d_n_traceback_els; n > 0; n--) {
+ traceback_t_ptr t_out_buf = (*t_out_bufs++);
+ for (size_t m = d_n_states; m > 0; m--, t_out_buf++) {
+ t_out_buf->d_prev = NULL;
+ t_out_buf->d_inputs = -1;
+ }
+ }
+#endif
+// set the fsm to "doing up"
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Set FSM to fsm_dec_doing_up\n";
+#endif
+ d_fsm = fsm_dec_doing_up;
+#if DO_PRINT_DEBUG_FSM
+ std::cout << "Exited fsm_dec_init\n";
+#endif
+ break;
+// should never get here!
+ default:
+ assert (0);
+// done (switch) with FSM
+ }
+// done (while) there are inputs
+ }
+
+// consume all of the input items on all input streams
+// "ninput_items[]" doesn't seem to be reliable,
+// so compute this from the actual number of frames processed
+#if DO_PRINT_DEBUG_EXIT
+ std::cout << "Exiting FSM in state: " <<
+ (d_fsm == fsm_dec_init ? "init" :
+ (d_fsm == fsm_dec_doing_up ? "up" :
+ (d_fsm == fsm_dec_doing_middle ? "middle" :
+ (d_fsm == fsm_dec_doing_term ? "term" :
+ (d_fsm == fsm_dec_output ? "output" : "unknown"))))) << "\n" <<
+ "Consuming " << t_in_buf_ndx <<
+ " input items on each input stream (of " << t_ninput_items << ").\n";
+#endif
+ consume_each (t_in_buf_ndx);
+
+// make sure the number of output items makes sense
+// t_out_buf_ndx always points to the current index
+// t_out_bit_shift always points to the next bit position to be written
+ int t_leftover_bytes = t_out_buf_ndx % d_out_stream_el_size_bytes;
+ int t_leftover_bits = ((t_leftover_bytes * g_num_bits_per_byte) +
+ t_out_bit_shift);
+ int t_noutput_items = noutput_items;
+#if DO_PRINT_DEBUG_EXIT
+ std::cout << "Final o_b[" << t_out_buf_ndx << "][" <<
+ t_out_bit_shift << "] of " << t_noutput_bytes <<
+ ", el_size = " << d_out_stream_el_size_bytes <<
+ ", lo_Bytes = " << t_leftover_bytes <<
+ ", t_lo_bits = " << t_leftover_bits << "\n" <<
+ "Desired # output items = " << noutput_items << "\n";
+#endif
+ if (t_leftover_bits != 0) {
+ // should never get here!
+#if 1
+ assert (0);
+#else
+ int t_ndx = t_out_buf_ndx - t_leftover_bytes;
+ size_t t_n_copy = t_leftover_bytes + ((t_out_bit_shift != 0) ? 1 : 0);
+ assert (t_n_copy <= d_out_stream_el_size_bytes);
+// copy the leftover into the save buffer
+ for (size_t n = 0; n < d_n_code_inputs; n++) {
+ bcopy (&(out_buf[n][t_ndx]), d_save_buffer[n], t_n_copy);
+ }
+ t_noutput_items = t_ndx / d_out_stream_el_size_bytes;
+ d_n_saved_bits = t_leftover_bits;
+#if DO_PRINT_DEBUG_EXIT
+ std::cout << "Copied " << t_n_copy << " Byte" <<
+ (t_n_copy != 1 ? "s" : "") << " from o_b[][" << t_ndx <<
+ "] into each save buffer.\n" <<
+ "Actual #output items = " << t_noutput_items <<
+ ", # saved bit(s) = " << d_n_saved_bits << "\n";
+#endif
+#endif
+ }
+
+#if DO_TIME_THOUGHPUT
+ u_long d_t = end_timer (&t_tp);
+
+ std::cout << "dec_blk_conv_soft_full: Completed " << t_ninput_items <<
+ " bits in " << d_t << " usec => " <<
+ 1e6*(((double)(t_ninput_items))/((double) d_t)) <<
+ " b/s\n";
+#endif
+
+// returns number of items written to each output stream
+ return (t_noutput_items);
+}
Index: gr_decoder_viterbi_block_soft_full.h
===================================================================
RCS file: gr_decoder_viterbi_block_soft_full.h
diff -N gr_decoder_viterbi_block_soft_full.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_decoder_viterbi_block_soft_full.h 3 Jul 2006 02:12:53 -0000
1.1
@@ -0,0 +1,238 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio.
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_GR_DECODER_VITERBI_BLOCK_SOFT_FULL_H
+#define INCLUDED_GR_DECODER_VITERBI_BLOCK_SOFT_FULL_H
+
+#include <gr_block.h>
+#include <vector>
+#include <sys/types.h>
+
+struct state_t;
+
+/*
+ * connection_t: describes an output connection from the current
+ * time-bit memory state to the next time-bit memory state
+ *
+ * d_to: state pointer to which this connection going
+ *
+ * d_to_ndx: index of the "to" state
+ *
+ * d_output_bits: what are the output bits, coverted into
+ * 1->+1.0, 0->-1.0, for this connection
+ */
+
+typedef struct connection_t {
+ struct state_t *d_to;
+ int d_to_ndx;
+ float* d_output_bits;
+} connection_t, *connection_t_ptr;
+
+/*
+ * state_t: describes a given memory state
+ *
+ * d_connections: a pointer to an array of these structures
+ * will be used to describes a given time-bit's memory state;
+ * an entry will be referenced via "state_add_to", to find the
+ * connections to the next time-bit memory states. There is
+ * one entry per each input bit combination -> 2^#I connections in all.
+ * e.g. [0] means the all 0 input;
+ * [1] means that input #1 was 1 while all the others were 0;
+ * [2] means that input #2 was 1, while all the others were 0;
+ * [3] means that inputs #1 and #2 were 1, while the others were 0.
+ *
+ * d_max_metric: the maximum metric thus far for this state
+ *
+ * d_max_state: the state from which the maximum metric was attained
+ *
+ * d_max_input: the input bits from which the maximum metric was attained
+ */
+
+typedef struct state_t {
+ connection_t_ptr d_connections;
+ float d_max_metric;
+ int d_max_state_ndx;
+ int d_max_input;
+} state_t, *state_t_ptr;
+
+/*
+ * state_get_from(v,i,k): use to retrieve a given bit-memory state,
+ * from the inputs:
+ *
+ * int v: the value from which to retrieve the given state
+ * int i: for which input stream (0 to #I-1)
+ * int k: the number of memory slots per input (e.g. 1+D^2 -> 2)
+ */
+
+#define state_get_from(v,i,k) (((v)>>((i)*(k)))&((1<<(k))-1))
+
+/*
+ * state_add_to(s,i,v,k): use to create a given bit-memory state,
+ * from the inputs:
+ *
+ * int s: the state value to modify
+ * int i: for which input stream (0 to #I-1)
+ * int v: value to set the state to for this input
+ * int k: the number of memory slots per input (e.g. 1+D^2 -> 2)
+ */
+
+#define state_add_to(s,v,i,k) (s)|=(((v)&((1<<(k))-1))<<((i)*(k)))
+
+/*
+ * fsm_dec_t: finite state machine for the decoder
+ *
+ * fsm_dec_init: initialize for a new frame / block; this is already
+ * done at instantiation, so do it only at the end of a block.
+ *
+ * fsm_dec_doing_up: starting the trellis; done for all types
+ *
+ * fsm_dec_doing_middle: full trellis; done for all types
+ *
+ * fsm_dec_doing_term: termination trellis, if requested
+ *
+ * fsm_dec_doing_output: output all bits
+ */
+
+typedef enum {
+ fsm_dec_init, fsm_dec_doing_up, fsm_dec_doing_middle,
+ fsm_dec_doing_term, fsm_dec_output
+} fsm_dec_t;
+
+/*
+ * traceback_t: used to store all encode-input bits for
+ * all possible paths, when computing all trellis bits before
+ * determining the ML decode-output sequence.
+ *
+ * d_prev: the connection to the previous bit's traceback structure
+ *
+ * d_inputs: the inputs (one per bit) for this connection
+ */
+
+typedef struct traceback_t {
+ struct traceback_t *d_prev;
+ int d_inputs;
+} traceback_t, *traceback_t_ptr, **traceback_t_hdl;
+
+// GR stuff
+
+class gr_decoder_viterbi_block_soft_full;
+typedef boost::shared_ptr<gr_decoder_viterbi_block_soft_full>
+gr_decoder_viterbi_block_soft_full_sptr;
+
+gr_decoder_viterbi_block_soft_full_sptr gr_make_dec_blk_conv_soft_full
+(int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination);
+
+/*!
+ * \brief Decode the incoming streams using a Viterbi-style decoder
+ *
+ * input: encoded data as soft symbols, either as individual
+ * streams or mux'ed into 1 stream.
+ *
+ * output: stream(s) of user-defined element size.
+ */
+
+class gr_decoder_viterbi_block_soft_full : public gr_block
+{
+ friend gr_decoder_viterbi_block_soft_full_sptr
+ gr_make_dec_blk_conv_soft_full (int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination);
+/*
+ * frame_size_bits: if == 0, then do streaming decoding (infinite
+ * trellis); otherwise this is the block size to decode before
+ * terminating the trellis.
+ *
+ * code_generator: vector of integers (32 bit) representing the code
+ * to be implemented in octal form. E.g. "04" in binary is "100",
+ * which would be "D^2" for code generation. "06" == 110b == "D^2 + D"
+ * ==> The vector is listed in order for each input stream, so if there
+ * are 2 input streams (I1, I2) [specified in "n_code_inputs"]
+ * and 2 output streams (O1, O2) [specified in "n_code_outputs"],
+ * then the vector would be the code generator for:
+ * [I1->O1, I1->O2, I2->O1, I2->O2]
+ * with each element being the octal representation of the code.
+ *
+ * do_termination is valid only if frame_size_bits != 0, and defines
+ * whether or not to to trellis termination.
+ *
+ * do_mux_input: is true, then the one input stream will be
+ * interpreted as the multiplexing all of the input bits. For
+ * example for a 3 input decoder, the input stream would be
+ * [I1[k], I2[k], I3[k], I1[k+1], I2[k+1], ...], where "k" is the
+ * input sample time, and "I1" through "I3" are the 3 input
+ * streams.
+ *
+ * n_code_inputs: the number of decoder-input (encoder-output)
+ * streams, no matter if separate or mux'ed
+ *
+ * n_code_outputs: the number of decoder-output (encoder-input) streams
+ */
+
+ gr_decoder_viterbi_block_soft_full (int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination);
+
+public:
+ ~gr_decoder_viterbi_block_soft_full ();
+
+ virtual void forecast (int noutput_items,
+ gr_vector_int &ninput_items_required);
+
+ virtual int general_work (int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+
+ virtual int fixed_rate_noutput_to_ninput (int noutput_items);
+
+private:
+ void reset_metrics (u_char which);
+ void zero_metrics (u_char which);
+
+/*
+ * d_n_total_input_bits_per_stream: how many bits to store for each
+ * state to determine the best decoder-output (encoder-input) bits
+ */
+ size_t d_frame_size_bits;
+ size_t d_n_code_outputs, d_n_code_inputs, d_max_memory;
+ size_t d_time_count, d_n_total_input_bits_per_stream;
+ size_t d_n_saved_bits, d_n_saved_bits_start_ndx, d_n_traceback_els;
+ size_t d_n_states, d_n_input_combinations;
+ size_t d_states_ndx, d_up_term_ndx;
+ bool d_do_streaming, d_do_termination, d_do_mux_inputs;
+ char **d_save_buffer;
+ std::vector<int> d_code_generators;
+ state_t_ptr d_states[2];
+ fsm_dec_t d_fsm;
+ size_t* d_up_term_states_ndx[2];
+ traceback_t_hdl d_out_buf;
+};
+
+#endif /* INCLUDED_GR_DECODER_VITERBI_BLOCK_SOFT_FULL_H */
Index: gr_decoder_viterbi_block_soft_full.i
===================================================================
RCS file: gr_decoder_viterbi_block_soft_full.i
diff -N gr_decoder_viterbi_block_soft_full.i
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_decoder_viterbi_block_soft_full.i 3 Jul 2006 02:12:53 -0000
1.1
@@ -0,0 +1,39 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,dec_blk_conv_soft_full);
+
+gr_decoder_viterbi_block_soft_full_sptr
+gr_make_decoder_viterbi_block_soft_full (int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination);
+
+class gr_decoder_viterbi_block_soft_full : public gr_block
+{
+ gr_decoder_viterbi_block_soft_full (int frame_size_bits,
+ int num_input_streams,
+ int num_output_streams,
+ std::vector<int> code_generator,
+ bool do_termination);
+};
Index: gr_streams_encode_convolutional.cc
===================================================================
RCS file: gr_streams_encode_convolutional.cc
diff -N gr_streams_encode_convolutional.cc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_streams_encode_convolutional.cc 3 Jul 2006 02:12:53 -0000 1.1
@@ -0,0 +1,137 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio.
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_streams_encode_convolutional.h>
+#include <gr_io_signature.h>
+#include <assert.h>
+#include <iostream>
+
+gr_streams_encode_convolutional_sptr
+gr_make_streams_encode_convolutional (int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> &code_generator,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state)
+{
+ return gr_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::gr_streams_encode_convolutional
+(int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> &code_generators,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state)
+ : 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);
+
+// 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, handle the rest internally
+ set_output_multiple (1);
+}
+
+gr_streams_encode_convolutional::~gr_streams_encode_convolutional
+()
+{
+ 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 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.
+ */
+
+void gr_streams_encode_convolutional::forecast
+(int noutput_items,
+ gr_vector_int &ninput_items_required)
+{
+ int ninput_items = d_encoder->compute_n_input_bits (noutput_items);
+ for (int n = ninput_items_required.size() - 1; n >= 0; 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)
+{
+ size_t 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);
+}
Index: gr_streams_encode_convolutional.h
===================================================================
RCS file: gr_streams_encode_convolutional.h
diff -N gr_streams_encode_convolutional.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_streams_encode_convolutional.h 3 Jul 2006 02:12:53 -0000 1.1
@@ -0,0 +1,120 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio.
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef INCLUDED_GR_STREAMS_ENCODE_CONVOLUTIONAL_H
+#define INCLUDED_GR_STREAMS_ENCODE_CONVOLUTIONAL_H
+
+#include <gr_block.h>
+#include <vector>
+#include <libecc/encoder_convolutional.h>
+#include <sys/types.h>
+
+class gr_streams_encode_convolutional;
+typedef boost::shared_ptr<gr_streams_encode_convolutional>
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,
+ std::vector<int> &code_generator,
+ bool do_termination = true,
+ int start_memory_state = 0,
+ int end_memory_state = 0);
+
+/*!
+ * \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.
+ */
+
+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,
+ std::vector<int> &code_generator,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state);
+/*
+ * 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 in octal form. E.g. "04" in binary is "100",
+ * which would be "D^2" for code generation. "06" == 110b == "D^2 + D"
+ * ==> The vector is listed in order for each input stream, so if there
+ * are 2 input streams (I1, I2) [specified in "n_code_inputs"]
+ * and 2 output streams (O1, O2) [specified in "n_code_outputs"],
+ * then the vector would be the code generator for:
+ * [I1->O1, I1->O2, I2->O1, I2->O2]
+ * with each element being the octal representation of the code.
+ *
+ * do_termination: valid only if frame_size_bits != 0, and defines
+ * whether or not to use trellis termination. Default is to use
+ * termination when doing block coding.
+ *
+ * start_memory_state: when starting a new block, the starting memory
+ * state to begin encoding; there will be a helper function to
+ * assist in creating this value for a given set of inputs;
+ * default is the "all zero" state.
+ *
+ * end_memory_state: when terminating a block, the ending memory
+ * state to stop encoding; there will be a helper function to
+ * assist in creating this value for a given set of inputs;
+ * default is the "all zero" state.
+ */
+
+ gr_streams_encode_convolutional (int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> &code_generator,
+ bool do_termination = true,
+ int start_memory_state = 0,
+ int end_memory_state = 0);
+
+ encoder_convolutional* d_encoder;
+
+public:
+ ~gr_streams_encode_convolutional ();
+
+ 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 */
Index: gr_streams_encode_convolutional.i
===================================================================
RCS file: gr_streams_encode_convolutional.i
diff -N gr_streams_encode_convolutional.i
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_streams_encode_convolutional.i 3 Jul 2006 02:12:53 -0000 1.1
@@ -0,0 +1,43 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+GR_SWIG_BLOCK_MAGIC(gr,streams_encode_convolutional);
+
+gr_streams_encode_convolutional_sptr
+gr_make_streams_encode_convolutional (int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> &code_generator,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state);
+
+class gr_streams_encode_convolutional : public gr_block
+{
+ gr_streams_encode_convolutional (int frame_size_bits,
+ int n_code_inputs,
+ int n_code_outputs,
+ std::vector<int> &code_generator,
+ bool do_termination,
+ int start_memory_state,
+ int end_memory_state);
+};
Index: gr_syms_to_metrics.cc
===================================================================
RCS file: gr_syms_to_metrics.cc
diff -N gr_syms_to_metrics.cc
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_syms_to_metrics.cc 3 Jul 2006 02:12:53 -0000 1.1
@@ -0,0 +1,162 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_syms_to_metrics.h>
+#include <gr_io_signature.h>
+#include <assert.h>
+
+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 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 = 4;
+ d_code_metrics = new code_metric_ff (&pdf_fcn_0,
+ &pdf_fcn_1,
+ n_samples,
+ min_sample,
+ max_sample);
+ } else if (sample_precision <= 8) {
+// use char
+ d_out_item_size_bytes = 1;
+ 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 = 2;
+ 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 = 4;
+ 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);
+}
Index: gr_syms_to_metrics.h
===================================================================
RCS file: gr_syms_to_metrics.h
diff -N gr_syms_to_metrics.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_syms_to_metrics.h 3 Jul 2006 02:12:53 -0000 1.1
@@ -0,0 +1,121 @@
+/* -*- 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 <gr_block.h>
+#include <gr_feval.h>
+#include <vector>
+#include <libecc/code_metrics.h>
+
+class gr_syms_to_metrics;
+typedef boost::shared_ptr<gr_syms_to_metrics> 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 */
Index: gr_syms_to_metrics.i
===================================================================
RCS file: gr_syms_to_metrics.i
diff -N gr_syms_to_metrics.i
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gr_syms_to_metrics.i 3 Jul 2006 02:12:53 -0000 1.1
@@ -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(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);
+};
Index: qa_ecc.py
===================================================================
RCS file: qa_ecc.py
diff -N qa_ecc.py
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ qa_ecc.py 3 Jul 2006 02:12:53 -0000 1.1
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+#
+# Copyright 2006 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING. If not, write to
+# the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+#
+
+from gnuradio import gr, gr_unittest, ecc
+
+class qa_error-correcting-codes (gr_unittest.TestCase):
+
+ def setUp (self):
+ self.fg = gr.flow_graph ()
+
+ def tearDown (self):
+ self.fg = None
+
+ def test_000_nop (self):
+ """Just see if we can import the module...
+ They may not have drivers, etc. Don't try to run anything"""
+ pass
+
+if __name__ == '__main__':
+ gr_unittest.main ()
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] gr-error-correcting-codes/src/lib Makefile.am _...,
Michael Dickens <=