summaryrefslogtreecommitdiff
path: root/gr-trellis/lib
diff options
context:
space:
mode:
Diffstat (limited to 'gr-trellis/lib')
-rw-r--r--gr-trellis/lib/CMakeLists.txt139
-rw-r--r--gr-trellis/lib/base.cc86
-rw-r--r--gr-trellis/lib/calc_metric.cc251
-rw-r--r--gr-trellis/lib/constellation_metrics_cf_impl.cc96
-rw-r--r--gr-trellis/lib/constellation_metrics_cf_impl.h57
-rw-r--r--gr-trellis/lib/core_algorithms.cc1324
-rw-r--r--gr-trellis/lib/encoder_XX_impl.cc.t82
-rw-r--r--gr-trellis/lib/encoder_XX_impl.h.t54
-rw-r--r--gr-trellis/lib/fsm.cc521
-rw-r--r--gr-trellis/lib/interleaver.cc147
-rw-r--r--gr-trellis/lib/metrics_X_impl.cc.t98
-rw-r--r--gr-trellis/lib/metrics_X_impl.h.t64
-rw-r--r--gr-trellis/lib/pccc_decoder_X_impl.cc.t120
-rw-r--r--gr-trellis/lib/pccc_decoder_X_impl.h.t80
-rw-r--r--gr-trellis/lib/pccc_decoder_combined_XX_impl.cc.t139
-rw-r--r--gr-trellis/lib/pccc_decoder_combined_XX_impl.h.t93
-rw-r--r--gr-trellis/lib/pccc_encoder_XX_impl.cc.t91
-rw-r--r--gr-trellis/lib/pccc_encoder_XX_impl.h.t66
-rw-r--r--gr-trellis/lib/permutation_impl.cc90
-rw-r--r--gr-trellis/lib/permutation_impl.h58
-rw-r--r--gr-trellis/lib/quicksort_index.cc70
-rw-r--r--gr-trellis/lib/sccc_decoder_X_impl.cc.t118
-rw-r--r--gr-trellis/lib/sccc_decoder_X_impl.h.t80
-rw-r--r--gr-trellis/lib/sccc_decoder_combined_XX_impl.cc.t139
-rw-r--r--gr-trellis/lib/sccc_decoder_combined_XX_impl.h.t93
-rw-r--r--gr-trellis/lib/sccc_encoder_XX_impl.cc.t93
-rw-r--r--gr-trellis/lib/sccc_encoder_XX_impl.h.t66
-rw-r--r--gr-trellis/lib/siso_combined_f_impl.cc180
-rw-r--r--gr-trellis/lib/siso_combined_f_impl.h79
-rw-r--r--gr-trellis/lib/siso_f_impl.cc171
-rw-r--r--gr-trellis/lib/siso_f_impl.h75
-rw-r--r--gr-trellis/lib/viterbi_X_impl.cc.t99
-rw-r--r--gr-trellis/lib/viterbi_X_impl.h.t65
-rw-r--r--gr-trellis/lib/viterbi_combined_XX_impl.cc.t112
-rw-r--r--gr-trellis/lib/viterbi_combined_XX_impl.h.t74
35 files changed, 5170 insertions, 0 deletions
diff --git a/gr-trellis/lib/CMakeLists.txt b/gr-trellis/lib/CMakeLists.txt
new file mode 100644
index 0000000000..5bd0227de6
--- /dev/null
+++ b/gr-trellis/lib/CMakeLists.txt
@@ -0,0 +1,139 @@
+# Copyright 2012 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 3, 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., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+
+########################################################################
+# Setup the include and linker paths
+########################################################################
+include_directories(
+ ${GNURADIO_CORE_INCLUDE_DIRS}
+ ${GR_TRELLIS_INCLUDE_DIRS}
+ ${GR_DIGITAL_INCLUDE_DIRS}
+ ${CMAKE_CURRENT_BINARY_DIR}/../include
+)
+
+include_directories(${Boost_INCLUDE_DIRS})
+link_directories(${Boost_LIBRARY_DIRS})
+
+if(ENABLE_GR_CTRLPORT)
+ ADD_DEFINITIONS(-DGR_CTRLPORT)
+endif(ENABLE_GR_CTRLPORT)
+
+#######################################################################
+# generate the python helper script which calls into the build utils
+########################################################################
+include(GrPython)
+
+file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py "
+#!${PYTHON_EXECUTABLE}
+
+import sys, os, re
+sys.path.append('${GR_CORE_PYTHONPATH}')
+os.environ['srcdir'] = '${CMAKE_CURRENT_SOURCE_DIR}'
+os.chdir('${CMAKE_CURRENT_BINARY_DIR}')
+
+if __name__ == '__main__':
+ import build_utils
+ root, inp = sys.argv[1:3]
+ for sig in sys.argv[3:]:
+ name = re.sub ('X+', sig, root)
+ d = build_utils.standard_impl_dict2(name, sig, 'trellis')
+ build_utils.expand_template(d, inp)
+")
+
+macro(expand_cc root)
+ #make a list of all the generated files
+ unset(expanded_files_cc)
+ unset(expanded_files_h)
+ foreach(sig ${ARGN})
+ string(REGEX REPLACE "X+" ${sig} name ${root})
+ list(APPEND expanded_files_cc ${CMAKE_CURRENT_BINARY_DIR}/${name}.cc)
+ list(APPEND expanded_files_h ${CMAKE_CURRENT_BINARY_DIR}/${name}.h)
+ endforeach(sig)
+
+ #create a command to generate the source files
+ add_custom_command(
+ OUTPUT ${expanded_files_cc}
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.cc.t
+ COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
+ ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
+ ${root} ${root}.cc.t ${ARGN}
+ )
+
+ #create a command to generate the header file
+ add_custom_command(
+ OUTPUT ${expanded_files_h}
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${root}.h.t
+ COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B}
+ ${CMAKE_CURRENT_BINARY_DIR}/generate_helper.py
+ ${root} ${root}.h.t ${ARGN}
+ )
+
+ #make source files depends on headers to force generation
+ set_source_files_properties(${expanded_files_cc}
+ PROPERTIES OBJECT_DEPENDS "${expanded_files_h}"
+ )
+
+ #install rules for the generated cc files
+ list(APPEND generated_sources ${expanded_files_cc})
+ list(APPEND generated_headers ${expanded_files_h})
+endmacro(expand_cc)
+
+########################################################################
+# Invoke macro to generate various sources
+########################################################################
+expand_cc(encoder_XX_impl bb bs bi ss si ii)
+expand_cc(sccc_encoder_XX_impl bb bs bi ss si ii)
+expand_cc(pccc_encoder_XX_impl bb bs bi ss si ii)
+expand_cc(metrics_X_impl s i f c)
+expand_cc(viterbi_X_impl b s i)
+expand_cc(viterbi_combined_XX_impl sb ss si ib is ii fb fs fi cb cs ci)
+expand_cc(sccc_decoder_X_impl b s i)
+expand_cc(sccc_decoder_combined_XX_impl fb fs fi cb cs ci)
+expand_cc(pccc_decoder_X_impl b s i)
+expand_cc(pccc_decoder_combined_XX_impl fb fs fi cb cs ci)
+
+########################################################################
+# Setup library
+########################################################################
+list(APPEND trellis_sources
+ ${generated_sources}
+ base.cc
+ calc_metric.cc
+ core_algorithms.cc
+ fsm.cc
+ interleaver.cc
+ quicksort_index.cc
+ constellation_metrics_cf_impl.cc
+ permutation_impl.cc
+ siso_f_impl.cc
+ siso_combined_f_impl.cc
+)
+
+list(APPEND trellis_libs
+ gnuradio-core
+ gnuradio-digital
+ ${Boost_LIBRARIES}
+)
+
+add_library(gnuradio-trellis SHARED ${trellis_sources})
+target_link_libraries(gnuradio-trellis ${trellis_libs})
+GR_LIBRARY_FOO(gnuradio-trellis RUNTIME_COMPONENT "trellis_runtime" DEVEL_COMPONENT "trellis_devel")
+add_dependencies(gnuradio-trellis
+ trellis_generated_includes trellis_generated_swigs
+ gnuradio-core gnuradio-digital)
diff --git a/gr-trellis/lib/base.cc b/gr-trellis/lib/base.cc
new file mode 100644
index 0000000000..e9d0141e70
--- /dev/null
+++ b/gr-trellis/lib/base.cc
@@ -0,0 +1,86 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2002,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <cstdio>
+#include <stdexcept>
+#include <cmath>
+#include <trellis/base.h>
+
+namespace gr {
+ namespace trellis {
+
+ bool
+ dec2base(unsigned int num, int base, std::vector<int> &s)
+ {
+ int l = s.size();
+ unsigned int n=num;
+ for(int i=0;i<l;i++) {
+ s[l-i-1] = n % base; //MSB first
+ n /= base;
+ }
+ if(n!=0) {
+ printf("Number %d requires more than %d digits.",num,l);
+ return false;
+ }
+ else
+ return true;
+ }
+
+ unsigned int
+ base2dec(const std::vector<int> &s, int base)
+ {
+ int l = s.size();
+ unsigned int num=0;
+ for(int i=0;i<l;i++)
+ num=num*base+s[i];
+ return num;
+ }
+
+ bool
+ dec2bases(unsigned int num, const std::vector<int> &bases, std::vector<int> &s)
+ {
+ int l = s.size();
+ unsigned int n=num;
+ for(int i=0;i<l;i++) {
+ s[l-i-1] = n % bases[l-i-1];
+ n /= bases[l-i-1];
+ }
+ if(n!=0) {
+ printf("Number %d requires more than %d digits.",num,l);
+ return false;
+ }
+ else
+ return true;
+ }
+
+ unsigned int
+ bases2dec(const std::vector<int> &s, const std::vector<int> &bases)
+ {
+ int l = s.size();
+ unsigned int num=0;
+ for(int i=0;i<l;i++)
+ num = num * bases[i] + s[i];
+ return num;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/calc_metric.cc b/gr-trellis/lib/calc_metric.cc
new file mode 100644
index 0000000000..3c474e30fe
--- /dev/null
+++ b/gr-trellis/lib/calc_metric.cc
@@ -0,0 +1,251 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <float.h>
+#include <stdexcept>
+#include <trellis/calc_metric.h>
+
+namespace gr {
+ namespace trellis {
+
+ template <class T>
+ void calc_metric(int O, int D, const std::vector<T> &TABLE, const T *input,
+ float *metric, digital::trellis_metric_type_t type)
+ {
+ float minm = FLT_MAX;
+ int minmi = 0;
+
+ switch(type) {
+ case digital::TRELLIS_EUCLIDEAN:
+ for(int o = 0; o < O; o++) {
+ metric[o] = 0.0;
+ for(int m = 0; m < D; m++) {
+ T s = input[m]-TABLE[o*D+m];
+ //gr_complex sc(1.0*s,0);
+ //metric[o] += (sc*conj(sc)).real();
+ metric[o] += s * s;
+ }
+ }
+ break;
+ case digital::TRELLIS_HARD_SYMBOL:
+ for(int o = 0; o < O; o++) {
+ metric[o] = 0.0;
+ for(int m = 0; m < D; m++) {
+ T s = input[m]-TABLE[o*D+m];
+ //gr_complex sc(1.0*s,0);
+ //metric[o] + =(sc*conj(sc)).real();
+ metric[o] += s * s;
+ }
+ if(metric[o] < minm) {
+ minm = metric[o];
+ minmi = o;
+ }
+ }
+ for(int o = 0; o < O; o++) {
+ metric[o] = (o == minmi ? 0.0 : 1.0);
+ }
+ break;
+ case digital::TRELLIS_HARD_BIT:
+ throw std::runtime_error("calc_metric: Invalid metric type (not yet implemented).");
+ break;
+ default:
+ throw std::runtime_error("calc_metric: Invalid metric type.");
+ }
+ }
+
+ template
+ void calc_metric<short>(int O, int D, const std::vector<short> &TABLE, const short *input,
+ float *metric, digital::trellis_metric_type_t type);
+
+ template
+ void calc_metric<int>(int O, int D, const std::vector<int> &TABLE, const int *input,
+ float *metric, digital::trellis_metric_type_t type);
+
+ template
+ void calc_metric<float>(int O, int D, const std::vector<float> &TABLE, const float *input,
+ float *metric, digital::trellis_metric_type_t type);
+
+ void calc_metric(int O, int D, const std::vector<short> &TABLE, const short *input,
+ float *metric, digital::trellis_metric_type_t type)
+ {
+ float minm = FLT_MAX;
+ int minmi = 0;
+
+ switch(type) {
+ case digital::TRELLIS_EUCLIDEAN:
+ for(int o = 0; o < O; o++) {
+ metric[o] = 0.0;
+ for(int m = 0; m < D; m++) {
+ float s = input[m]-TABLE[o*D+m];
+ metric[o] += s*s;
+ }
+ }
+ break;
+ case digital::TRELLIS_HARD_SYMBOL:
+ for(int o = 0; o < O; o++) {
+ metric[o] = 0.0;
+ for(int m = 0; m < D; m++) {
+ float s = input[m]-TABLE[o*D+m];
+ metric[o] += s*s;
+ }
+ if(metric[o] < minm) {
+ minm = metric[o];
+ minmi = o;
+ }
+ }
+ for(int o = 0; o < O; o++) {
+ metric[o] = (o == minmi ? 0.0 : 1.0);
+ }
+ break;
+ case digital::TRELLIS_HARD_BIT:
+ throw std::runtime_error("calc_metric: Invalid metric type (not yet implemented).");
+ break;
+ default:
+ throw std::runtime_error("calc_metric: Invalid metric type.");
+ }
+ }
+
+ /*
+ void calc_metric(int O, int D, const std::vector<int> &TABLE, const int *input,
+ float *metric, digital::trellis_metric_type_t type)
+ {
+ float minm = FLT_MAX;
+ int minmi = 0;
+
+ switch(type){
+ case digital::TRELLIS_EUCLIDEAN:
+ for(int o=0;o<O;o++) {
+ metric[o]=0.0;
+ for(int m=0;m<D;m++) {
+ float s=input[m]-TABLE[o*D+m];
+ metric[o]+=s*s;
+ }
+ }
+ break;
+ case digital::TRELLIS_HARD_SYMBOL:
+ for(int o=0;o<O;o++) {
+ metric[o]=0.0;
+ for(int m=0;m<D;m++) {
+ float s=input[m]-TABLE[o*D+m];
+ metric[o]+=s*s;
+ }
+ if(metric[o]<minm) {
+ minm=metric[o];
+ minmi=o;
+ }
+ }
+ for(int o=0;o<O;o++) {
+ metric[o] = (o==minmi?0.0:1.0);
+ }
+ break;
+ case digital::TRELLIS_HARD_BIT:
+ throw std::runtime_error("calc_metric: Invalid metric type (not yet implemented).");
+ break;
+ default:
+ throw std::runtime_error("calc_metric: Invalid metric type.");
+ }
+ }
+
+ void calc_metric(int O, int D, const std::vector<float> &TABLE, const float *input,
+ float *metric, digital::trellis_metric_type_t type)
+ {
+ float minm = FLT_MAX;
+ int minmi = 0;
+
+ switch(type) {
+ case digital::TRELLIS_EUCLIDEAN:
+ for(int o=0;o<O;o++) {
+ metric[o]=0.0;
+ for(int m=0;m<D;m++) {
+ float s=input[m]-TABLE[o*D+m];
+ metric[o]+=s*s;
+ }
+ }
+ break;
+ case digital::TRELLIS_HARD_SYMBOL:
+ for(int o=0;o<O;o++) {
+ metric[o]=0.0;
+ for(int m=0;m<D;m++) {
+ float s=input[m]-TABLE[o*D+m];
+ metric[o]+=s*s;
+ }
+ if(metric[o]<minm) {
+ minm=metric[o];
+ minmi=o;
+ }
+ }
+ for(int o=0;o<O;o++) {
+ metric[o] = (o==minmi?0.0:1.0);
+ }
+ break;
+ case digital::TRELLIS_HARD_BIT:
+ throw std::runtime_error("calc_metric: Invalid metric type (not yet implemented).");
+ break;
+ default:
+ throw std::runtime_error("calc_metric: Invalid metric type.");
+ }
+ }
+*/
+
+ void calc_metric(int O, int D, const std::vector<gr_complex> &TABLE, const gr_complex *input,
+ float *metric, digital::trellis_metric_type_t type)
+ {
+ float minm = FLT_MAX;
+ int minmi = 0;
+
+ switch(type) {
+ case digital::TRELLIS_EUCLIDEAN:
+ for(int o = 0; o < O; o++) {
+ metric[o] = 0.0;
+ for(int m = 0; m < D; m++) {
+ gr_complex s = input[m]-TABLE[o*D+m];
+ metric[o] += s.real()*s.real()+s.imag()*s.imag();
+ }
+ }
+ break;
+ case digital::TRELLIS_HARD_SYMBOL:
+ for(int o = 0; o < O; o++) {
+ metric[o] = 0.0;
+ for(int m = 0; m < D; m++) {
+ gr_complex s = input[m]-TABLE[o*D+m];
+ metric[o] += s.real()*s.real()+s.imag()*s.imag();
+ }
+ if(metric[o] < minm) {
+ minm = metric[o];
+ minmi = o;
+ }
+ }
+ for(int o = 0; o < O; o++) {
+ metric[o] = (o == minmi ? 0.0 : 1.0);
+ }
+ break;
+ case digital::TRELLIS_HARD_BIT:
+ throw std::runtime_error("calc_metric: Invalid metric type (not yet implemented).");
+ break;
+ default:
+ throw std::runtime_error("calc_metric: Invalid metric type.");
+ }
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
+
diff --git a/gr-trellis/lib/constellation_metrics_cf_impl.cc b/gr-trellis/lib/constellation_metrics_cf_impl.cc
new file mode 100644
index 0000000000..18d3095802
--- /dev/null
+++ b/gr-trellis/lib/constellation_metrics_cf_impl.cc
@@ -0,0 +1,96 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010-2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "constellation_metrics_cf_impl.h"
+#include <gr_io_signature.h>
+#include <assert.h>
+#include <stdexcept>
+#include <iostream>
+
+namespace gr {
+ namespace trellis {
+
+ constellation_metrics_cf::sptr
+ constellation_metrics_cf::make(digital::constellation_sptr constellation,
+ digital::trellis_metric_type_t TYPE)
+ {
+ return gnuradio::get_initial_sptr
+ (new constellation_metrics_cf_impl(constellation, TYPE));
+ }
+
+ constellation_metrics_cf_impl::constellation_metrics_cf_impl(digital::constellation_sptr constellation,
+ digital::trellis_metric_type_t TYPE)
+ : gr_block("constellation_metrics_cf",
+ gr_make_io_signature(1, -1, sizeof(gr_complex)),
+ gr_make_io_signature(1, -1, sizeof(float))),
+ d_constellation(constellation),
+ d_TYPE(TYPE),
+ d_O(constellation->arity()),
+ d_D(constellation->dimensionality())
+ {
+ set_relative_rate(1.0 * d_O / ((double) d_D));
+ set_output_multiple((int)d_O);
+ }
+
+ constellation_metrics_cf_impl::~constellation_metrics_cf_impl()
+ {
+ }
+
+ void
+ constellation_metrics_cf_impl::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ assert(noutput_items % d_O == 0);
+
+ unsigned int input_required = d_D * noutput_items / d_O;
+ unsigned int ninputs = ninput_items_required.size();
+ for(unsigned int i = 0; i < ninputs; i++)
+ ninput_items_required[i] = input_required;
+ }
+
+ int
+ constellation_metrics_cf_impl::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ unsigned int nstreams = input_items.size();
+
+ for(unsigned int m=0;m<nstreams;m++) {
+ const gr_complex *in = (gr_complex*)input_items[m];
+ float *out = (float*)output_items[m];
+
+ for(unsigned int i = 0; i < noutput_items / d_O ; i++) {
+ d_constellation->calc_metric(&(in[i*d_D]), &(out[i*d_O]), d_TYPE);
+ }
+ }
+
+ consume_each(d_D * noutput_items / d_O);
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/constellation_metrics_cf_impl.h b/gr-trellis/lib/constellation_metrics_cf_impl.h
new file mode 100644
index 0000000000..52018c4baa
--- /dev/null
+++ b/gr-trellis/lib/constellation_metrics_cf_impl.h
@@ -0,0 +1,57 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010-2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_TRELLIS_CONSTELLATION_METRICS_CF_IMPL_H
+#define INCLUDED_TRELLIS_CONSTELLATION_METRICS_CF_IMPL_H
+
+#include <trellis/api.h>
+#include <trellis/constellation_metrics_cf.h>
+
+namespace gr {
+ namespace trellis {
+
+ class constellation_metrics_cf_impl : public constellation_metrics_cf
+ {
+ private:
+ digital::constellation_sptr d_constellation;
+ digital::trellis_metric_type_t d_TYPE;
+ unsigned int d_O;
+ unsigned int d_D;
+
+ public:
+ constellation_metrics_cf_impl(digital::constellation_sptr constellation,
+ digital::trellis_metric_type_t TYPE);
+ ~constellation_metrics_cf_impl();
+
+ 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);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* INCLUDED_TRELLIS_CONSTELLATION_METRICS_CF_IMPL_H */
diff --git a/gr-trellis/lib/core_algorithms.cc b/gr-trellis/lib/core_algorithms.cc
new file mode 100644
index 0000000000..a704e5f9a6
--- /dev/null
+++ b/gr-trellis/lib/core_algorithms.cc
@@ -0,0 +1,1324 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <cstring>
+#include <stdexcept>
+#include <iostream>
+#include <trellis/core_algorithms.h>
+#include <trellis/calc_metric.h>
+
+namespace gr {
+ namespace trellis {
+
+ static const float INF = 1.0e9;
+
+ float
+ min(float a, float b)
+ {
+ return a <= b ? a : b;
+ }
+
+ float
+ min_star(float a, float b)
+ {
+ return (a <= b ? a : b)-log(1+exp(a <= b ? a-b : b-a));
+ }
+
+ template <class T> void
+ viterbi_algorithm(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ const float *in, T *out)//,
+ //std::vector<int> &trace)
+ {
+ std::vector<int> trace(S*K);
+ std::vector<float> alpha(S*2);
+ int alphai;
+ float norm,mm,minm;
+ int minmi;
+ int st;
+
+ if(S0<0) { // initial state not specified
+ for(int i=0;i<S;i++) alpha[0*S+i]=0;
+ }
+ else {
+ for(int i=0;i<S;i++) alpha[0*S+i]=INF;
+ alpha[0*S+S0]=0.0;
+ }
+
+ alphai=0;
+ for(int k=0;k<K;k++) {
+ norm=INF;
+ for(int j=0;j<S;j++) { // for each next state do ACS
+ minm=INF;
+ minmi=0;
+ for(unsigned int i=0;i<PS[j].size();i++) {
+ //int i0 = j*I+i;
+ if((mm=alpha[alphai*S+PS[j][i]]+in[k*O+OS[PS[j][i]*I+PI[j][i]]])<minm)
+ minm=mm,minmi=i;
+ }
+ trace[k*S+j]=minmi;
+ alpha[((alphai+1)%2)*S+j]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int j=0;j<S;j++)
+ alpha[((alphai+1)%2)*S+j]-=norm; // normalize total metrics so they do not explode
+ alphai=(alphai+1)%2;
+ }
+
+ if(SK<0) { // final state not specified
+ minm=INF;
+ minmi=0;
+ for(int i=0;i<S;i++)
+ if((mm=alpha[alphai*S+i])<minm) minm=mm,minmi=i;
+ st=minmi;
+ }
+ else {
+ st=SK;
+ }
+
+ for(int k=K-1;k>=0;k--) { // traceback
+ int i0=trace[k*S+st];
+ out[k]= (T) PI[st][i0];
+ st=PS[st][i0];
+ }
+ }
+
+ template void
+ viterbi_algorithm<unsigned char>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ const float *in, unsigned char *out);
+
+ template void
+ viterbi_algorithm<short>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ const float *in, short *out);
+
+ template void
+ viterbi_algorithm<int>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ const float *in, int *out);
+
+ //==============================================
+
+ template <class Ti, class To> void
+ viterbi_algorithm_combined(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<Ti> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const Ti *in, To *out)
+ {
+ std::vector<int> trace(S*K);
+ std::vector<float> alpha(S*2);
+ float *metric = new float[O];
+ int alphai;
+ float norm,mm,minm;
+ int minmi;
+ int st;
+
+ if(S0<0) { // initial state not specified
+ for(int i=0;i<S;i++) alpha[0*S+i]=0;
+ }
+ else {
+ for(int i=0;i<S;i++) alpha[0*S+i]=INF;
+ alpha[0*S+S0]=0.0;
+ }
+
+ alphai=0;
+ for(int k=0;k<K;k++) {
+ calc_metric(O, D, TABLE, &(in[k*D]), metric,TYPE); // calc metrics
+ norm=INF;
+ for(int j=0;j<S;j++) { // for each next state do ACS
+ minm=INF;
+ minmi=0;
+ for(unsigned int i=0;i<PS[j].size();i++) {
+ //int i0 = j*I+i;
+ if((mm=alpha[alphai*S+PS[j][i]]+metric[OS[PS[j][i]*I+PI[j][i]]])<minm)
+ minm=mm,minmi=i;
+ }
+ trace[k*S+j]=minmi;
+ alpha[((alphai+1)%2)*S+j]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int j=0;j<S;j++)
+ alpha[((alphai+1)%2)*S+j]-=norm; // normalize total metrics so they do not explode
+ alphai=(alphai+1)%2;
+ }
+
+ if(SK<0) { // final state not specified
+ minm=INF;
+ minmi=0;
+ for(int i=0;i<S;i++)
+ if((mm=alpha[alphai*S+i])<minm) minm=mm,minmi=i;
+ st=minmi;
+ }
+ else {
+ st=SK;
+ }
+
+ for(int k=K-1;k>=0;k--) { // traceback
+ int i0=trace[k*S+st];
+ out[k]= (To) PI[st][i0];
+ st=PS[st][i0];
+ }
+
+ delete [] metric;
+ }
+
+ // Ti = s i f c
+ // To = b s i
+
+ //---------------
+
+ template void
+ viterbi_algorithm_combined<short,unsigned char>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<short> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const short *in, unsigned char *out);
+
+ template void
+ viterbi_algorithm_combined<int,unsigned char>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<int> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const int *in, unsigned char *out);
+
+ template void
+ viterbi_algorithm_combined<float,unsigned char>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const float *in, unsigned char *out);
+
+ template void
+ viterbi_algorithm_combined<gr_complex,unsigned char>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<gr_complex> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const gr_complex *in, unsigned char *out);
+
+ //---------------
+
+ template void
+ viterbi_algorithm_combined<short,short>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<short> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const short *in, short *out);
+
+ template void
+ viterbi_algorithm_combined<int,short>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<int> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const int *in, short *out);
+
+ template void
+ viterbi_algorithm_combined<float,short>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const float *in, short *out);
+
+ template void
+ viterbi_algorithm_combined<gr_complex,short>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<gr_complex> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const gr_complex *in, short *out);
+
+ //--------------
+
+ template void
+ viterbi_algorithm_combined<short,int>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<short> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const short *in, int *out);
+
+ template void
+ viterbi_algorithm_combined<int,int>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<int> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const int *in, int *out);
+
+ template void
+ viterbi_algorithm_combined<float,int>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const float *in, int *out);
+
+ template void
+ viterbi_algorithm_combined<gr_complex,int>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ int D,
+ const std::vector<gr_complex> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const gr_complex *in, int *out);
+
+ //===============================================
+
+ void
+ siso_algorithm(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ bool POSTI, bool POSTO,
+ float (*p2mymin)(float,float),
+ const float *priori, const float *prioro, float *post//,
+ //std::vector<float> &alpha,
+ //std::vector<float> &beta
+ )
+ {
+ float norm,mm,minm;
+ std::vector<float> alpha(S*(K+1));
+ std::vector<float> beta(S*(K+1));
+
+ if(S0<0) { // initial state not specified
+ for(int i=0;i<S;i++) alpha[0*S+i]=0;
+ }
+ else {
+ for(int i=0;i<S;i++) alpha[0*S+i]=INF;
+ alpha[0*S+S0]=0.0;
+ }
+
+ for(int k=0;k<K;k++) { // forward recursion
+ norm=INF;
+ for(int j=0;j<S;j++) {
+ minm=INF;
+ for(unsigned int i=0;i<PS[j].size();i++) {
+ //int i0 = j*I+i;
+ mm=alpha[k*S+PS[j][i]]+priori[k*I+PI[j][i]]+prioro[k*O+OS[PS[j][i]*I+PI[j][i]]];
+ minm=(*p2mymin)(minm,mm);
+ }
+ alpha[(k+1)*S+j]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int j=0;j<S;j++)
+ alpha[(k+1)*S+j]-=norm; // normalize total metrics so they do not explode
+ }
+
+ if(SK<0) { // final state not specified
+ for(int i=0;i<S;i++) beta[K*S+i]=0;
+ }
+ else {
+ for(int i=0;i<S;i++) beta[K*S+i]=INF;
+ beta[K*S+SK]=0.0;
+ }
+
+ for(int k=K-1;k>=0;k--) { // backward recursion
+ norm=INF;
+ for(int j=0;j<S;j++) {
+ minm=INF;
+ for(int i=0;i<I;i++) {
+ int i0 = j*I+i;
+ mm=beta[(k+1)*S+NS[i0]]+priori[k*I+i]+prioro[k*O+OS[i0]];
+ minm=(*p2mymin)(minm,mm);
+ }
+ beta[k*S+j]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int j=0;j<S;j++)
+ beta[k*S+j]-=norm; // normalize total metrics so they do not explode
+ }
+
+ if(POSTI && POSTO)
+ {
+ for(int k=0;k<K;k++) { // input combining
+ norm=INF;
+ for(int i=0;i<I;i++) {
+ minm=INF;
+ for(int j=0;j<S;j++) {
+ mm=alpha[k*S+j]+prioro[k*O+OS[j*I+i]]+beta[(k+1)*S+NS[j*I+i]];
+ minm=(*p2mymin)(minm,mm);
+ }
+ post[k*(I+O)+i]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int i=0;i<I;i++)
+ post[k*(I+O)+i]-=norm; // normalize metrics
+ }
+
+ for(int k=0;k<K;k++) { // output combining
+ norm=INF;
+ for(int n=0;n<O;n++) {
+ minm=INF;
+ for(int j=0;j<S;j++) {
+ for(int i=0;i<I;i++) {
+ mm= (n==OS[j*I+i] ? alpha[k*S+j]+priori[k*I+i]+beta[(k+1)*S+NS[j*I+i]] : INF);
+ minm=(*p2mymin)(minm,mm);
+ }
+ }
+ post[k*(I+O)+I+n]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int n=0;n<O;n++)
+ post[k*(I+O)+I+n]-=norm; // normalize metrics
+ }
+ }
+ else if(POSTI)
+ {
+ for(int k=0;k<K;k++) { // input combining
+ norm=INF;
+ for(int i=0;i<I;i++) {
+ minm=INF;
+ for(int j=0;j<S;j++) {
+ mm=alpha[k*S+j]+prioro[k*O+OS[j*I+i]]+beta[(k+1)*S+NS[j*I+i]];
+ minm=(*p2mymin)(minm,mm);
+ }
+ post[k*I+i]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int i=0;i<I;i++)
+ post[k*I+i]-=norm; // normalize metrics
+ }
+ }
+ else if(POSTO)
+ {
+ for(int k=0;k<K;k++) { // output combining
+ norm=INF;
+ for(int n=0;n<O;n++) {
+ minm=INF;
+ for(int j=0;j<S;j++) {
+ for(int i=0;i<I;i++) {
+ mm= (n==OS[j*I+i] ? alpha[k*S+j]+priori[k*I+i]+beta[(k+1)*S+NS[j*I+i]] : INF);
+ minm=(*p2mymin)(minm,mm);
+ }
+ }
+ post[k*O+n]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int n=0;n<O;n++)
+ post[k*O+n]-=norm; // normalize metrics
+ }
+ }
+ else
+ throw std::runtime_error("Not both POSTI and POSTO can be false.");
+ }
+
+ //===========================================================
+
+ template <class T> void
+ siso_algorithm_combined(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ bool POSTI, bool POSTO,
+ float (*p2mymin)(float,float),
+ int D,
+ const std::vector<T> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const float *priori, const T *observations, float *post)
+ {
+ float norm,mm,minm;
+ std::vector<float> alpha(S*(K+1));
+ std::vector<float> beta(S*(K+1));
+ float *prioro = new float[O*K];
+
+ if(S0<0) { // initial state not specified
+ for(int i=0;i<S;i++) alpha[0*S+i]=0;
+ }
+ else {
+ for(int i=0;i<S;i++) alpha[0*S+i]=INF;
+ alpha[0*S+S0]=0.0;
+ }
+
+ for(int k=0;k<K;k++) { // forward recursion
+ calc_metric(O, D, TABLE, &(observations[k*D]), &(prioro[k*O]),TYPE); // calc metrics
+ norm=INF;
+ for(int j=0;j<S;j++) {
+ minm=INF;
+ for(unsigned int i=0;i<PS[j].size();i++) {
+ //int i0 = j*I+i;
+ mm=alpha[k*S+PS[j][i]]+priori[k*I+PI[j][i]]+prioro[k*O+OS[PS[j][i]*I+PI[j][i]]];
+ minm=(*p2mymin)(minm,mm);
+ }
+ alpha[(k+1)*S+j]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int j=0;j<S;j++)
+ alpha[(k+1)*S+j]-=norm; // normalize total metrics so they do not explode
+ }
+
+ if(SK<0) { // final state not specified
+ for(int i=0;i<S;i++) beta[K*S+i]=0;
+ }
+ else {
+ for(int i=0;i<S;i++) beta[K*S+i]=INF;
+ beta[K*S+SK]=0.0;
+ }
+
+ for(int k=K-1;k>=0;k--) { // backward recursion
+ norm=INF;
+ for(int j=0;j<S;j++) {
+ minm=INF;
+ for(int i=0;i<I;i++) {
+ int i0 = j*I+i;
+ mm=beta[(k+1)*S+NS[i0]]+priori[k*I+i]+prioro[k*O+OS[i0]];
+ minm=(*p2mymin)(minm,mm);
+ }
+ beta[k*S+j]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int j=0;j<S;j++)
+ beta[k*S+j]-=norm; // normalize total metrics so they do not explode
+ }
+
+ if(POSTI && POSTO)
+ {
+ for(int k=0;k<K;k++) { // input combining
+ norm=INF;
+ for(int i=0;i<I;i++) {
+ minm=INF;
+ for(int j=0;j<S;j++) {
+ mm=alpha[k*S+j]+prioro[k*O+OS[j*I+i]]+beta[(k+1)*S+NS[j*I+i]];
+ minm=(*p2mymin)(minm,mm);
+ }
+ post[k*(I+O)+i]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int i=0;i<I;i++)
+ post[k*(I+O)+i]-=norm; // normalize metrics
+ }
+
+ for(int k=0;k<K;k++) { // output combining
+ norm=INF;
+ for(int n=0;n<O;n++) {
+ minm=INF;
+ for(int j=0;j<S;j++) {
+ for(int i=0;i<I;i++) {
+ mm= (n==OS[j*I+i] ? alpha[k*S+j]+priori[k*I+i]+beta[(k+1)*S+NS[j*I+i]] : INF);
+ minm=(*p2mymin)(minm,mm);
+ }
+ }
+ post[k*(I+O)+I+n]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int n=0;n<O;n++)
+ post[k*(I+O)+I+n]-=norm; // normalize metrics
+ }
+ }
+ else if(POSTI)
+ {
+ for(int k=0;k<K;k++) { // input combining
+ norm=INF;
+ for(int i=0;i<I;i++) {
+ minm=INF;
+ for(int j=0;j<S;j++) {
+ mm=alpha[k*S+j]+prioro[k*O+OS[j*I+i]]+beta[(k+1)*S+NS[j*I+i]];
+ minm=(*p2mymin)(minm,mm);
+ }
+ post[k*I+i]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int i=0;i<I;i++)
+ post[k*I+i]-=norm; // normalize metrics
+ }
+ }
+ else if(POSTO) {
+ for(int k=0;k<K;k++) { // output combining
+ norm=INF;
+ for(int n=0;n<O;n++) {
+ minm=INF;
+ for(int j=0;j<S;j++) {
+ for(int i=0;i<I;i++) {
+ mm= (n==OS[j*I+i] ? alpha[k*S+j]+priori[k*I+i]+beta[(k+1)*S+NS[j*I+i]] : INF);
+ minm=(*p2mymin)(minm,mm);
+ }
+ }
+ post[k*O+n]=minm;
+ if(minm<norm) norm=minm;
+ }
+ for(int n=0;n<O;n++)
+ post[k*O+n]-=norm; // normalize metrics
+ }
+ }
+ else
+ throw std::runtime_error ("Not both POSTI and POSTO can be false.");
+
+ delete [] prioro;
+ }
+
+ //---------
+
+ template void
+ siso_algorithm_combined<short>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ bool POSTI, bool POSTO,
+ float (*p2mymin)(float,float),
+ int D,
+ const std::vector<short> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const float *priori, const short *observations, float *post);
+
+ template void
+ siso_algorithm_combined<int>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ bool POSTI, bool POSTO,
+ float (*p2mymin)(float,float),
+ int D,
+ const std::vector<int> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const float *priori, const int *observations, float *post);
+
+ template void
+ siso_algorithm_combined<float>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ bool POSTI, bool POSTO,
+ float (*p2mymin)(float,float),
+ int D,
+ const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const float *priori, const float *observations, float *post);
+
+ template void
+ siso_algorithm_combined<gr_complex>(int I, int S, int O,
+ const std::vector<int> &NS,
+ const std::vector<int> &OS,
+ const std::vector< std::vector<int> > &PS,
+ const std::vector< std::vector<int> > &PI,
+ int K,
+ int S0,int SK,
+ bool POSTI, bool POSTO,
+ float (*p2mymin)(float,float),
+ int D,
+ const std::vector<gr_complex> &TABLE,
+ digital::trellis_metric_type_t TYPE,
+ const float *priori, const gr_complex *observations, float *post);
+
+ //=========================================================
+
+ template<class Ti, class To> void
+ sccc_decoder_combined(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER, int blocklength, int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<Ti> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const Ti *observations, To *data)
+ {
+ //allocate space for priori, prioro and posti of inner FSM
+ std::vector<float> ipriori(blocklength*FSMi.I(),0.0);
+ std::vector<float> iprioro(blocklength*FSMi.O());
+ std::vector<float> iposti(blocklength*FSMi.I());
+
+ //allocate space for priori, prioro and posto of outer FSM
+ std::vector<float> opriori(blocklength*FSMo.I(),0.0);
+ std::vector<float> oprioro(blocklength*FSMo.O());
+ std::vector<float> oposti(blocklength*FSMo.I());
+ std::vector<float> oposto(blocklength*FSMo.O());
+
+ // turn observations to neg-log-priors
+ for(int k=0;k<blocklength;k++) {
+ calc_metric(FSMi.O(), D, TABLE, &(observations[k*D]), &(iprioro[k*FSMi.O()]),METRIC_TYPE);
+ iprioro[k*FSMi.O()] *= scaling;
+ }
+
+ for(int rep=0;rep<iterations;rep++) {
+ // run inner SISO
+ siso_algorithm(FSMi.I(),FSMi.S(),FSMi.O(),
+ FSMi.NS(), FSMi.OS(), FSMi.PS(), FSMi.PI(),
+ blocklength,
+ STi0,STiK,
+ true, false,
+ p2mymin,
+ &(ipriori[0]), &(iprioro[0]), &(iposti[0]));
+
+ //interleave soft info inner -> outer
+ for(int k=0;k<blocklength;k++) {
+ int ki = INTERLEAVER.DEINTER()[k];
+ //for(int i=0;i<FSMi.I();i++) {
+ //oprioro[k*FSMi.I()+i]=iposti[ki*FSMi.I()+i];
+ //}
+ memcpy(&(oprioro[k*FSMi.I()]),&(iposti[ki*FSMi.I()]),FSMi.I()*sizeof(float));
+ }
+
+ // run outer SISO
+
+ if(rep<iterations-1) { // do not produce posti
+ siso_algorithm(FSMo.I(),FSMo.S(),FSMo.O(),
+ FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(),
+ blocklength,
+ STo0,SToK,
+ false, true,
+ p2mymin,
+ &(opriori[0]), &(oprioro[0]), &(oposto[0]));
+
+ //interleave soft info outer --> inner
+ for(int k=0;k<blocklength;k++) {
+ int ki = INTERLEAVER.DEINTER()[k];
+ //for(int i=0;i<FSMi.I();i++) {
+ //ipriori[ki*FSMi.I()+i]=oposto[k*FSMi.I()+i];
+ //}
+ memcpy(&(ipriori[ki*FSMi.I()]),&(oposto[k*FSMi.I()]),FSMi.I()*sizeof(float));
+ }
+ }
+ else // produce posti but not posto
+
+ siso_algorithm(FSMo.I(),FSMo.S(),FSMo.O(),
+ FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(),
+ blocklength,
+ STo0,SToK,
+ true, false,
+ p2mymin,
+ &(opriori[0]), &(oprioro[0]), &(oposti[0]));
+
+ /*
+ viterbi_algorithm(FSMo.I(),FSMo.S(),FSMo.O(),
+ FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(),
+ blocklength,
+ STo0,SToK,
+ &(oprioro[0]), data
+ );
+ */
+ }
+
+ // generate hard decisions
+ for(int k=0;k<blocklength;k++) {
+ float min=INF;
+ int mini=0;
+ for(int i=0;i<FSMo.I();i++) {
+ if(oposti[k*FSMo.I()+i]<min) {
+ min=oposti[k*FSMo.I()+i];
+ mini=i;
+ }
+ }
+ data[k]=(To)mini;
+ }
+ }
+
+ //-------
+
+ template void
+ sccc_decoder_combined<float,unsigned char>(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const float *observations, unsigned char *data);
+
+ template void
+ sccc_decoder_combined<float,short>(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const float *observations, short *data);
+
+ template void
+ sccc_decoder_combined<float,int>(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const float *observations, int *data);
+
+ template void
+ sccc_decoder_combined<gr_complex,unsigned char>(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<gr_complex> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const gr_complex *observations, unsigned char *data
+ );
+
+ template void
+ sccc_decoder_combined<gr_complex,short>(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<gr_complex> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const gr_complex *observations, short *data);
+
+ template void
+ sccc_decoder_combined<gr_complex,int>(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<gr_complex> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const gr_complex *observations, int *data);
+
+ //=========================================================
+
+ template<class T> void
+ sccc_decoder(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER, int blocklength, int iterations,
+ float (*p2mymin)(float,float),
+ const float *iprioro, T *data)
+ {
+ //allocate space for priori, and posti of inner FSM
+ std::vector<float> ipriori(blocklength*FSMi.I(),0.0);
+ std::vector<float> iposti(blocklength*FSMi.I());
+
+ //allocate space for priori, prioro and posto of outer FSM
+ std::vector<float> opriori(blocklength*FSMo.I(),0.0);
+ std::vector<float> oprioro(blocklength*FSMo.O());
+ std::vector<float> oposti(blocklength*FSMo.I());
+ std::vector<float> oposto(blocklength*FSMo.O());
+
+ for(int rep=0;rep<iterations;rep++) {
+ // run inner SISO
+ siso_algorithm(FSMi.I(),FSMi.S(),FSMi.O(),
+ FSMi.NS(), FSMi.OS(), FSMi.PS(), FSMi.PI(),
+ blocklength,
+ STi0,STiK,
+ true, false,
+ p2mymin,
+ &(ipriori[0]), &(iprioro[0]), &(iposti[0]));
+
+ //interleave soft info inner -> outer
+ for(int k=0;k<blocklength;k++) {
+ int ki = INTERLEAVER.DEINTER()[k];
+ //for(int i=0;i<FSMi.I();i++) {
+ //oprioro[k*FSMi.I()+i]=iposti[ki*FSMi.I()+i];
+ //}
+ memcpy(&(oprioro[k*FSMi.I()]),&(iposti[ki*FSMi.I()]),FSMi.I()*sizeof(float));
+ }
+
+ // run outer SISO
+
+ if(rep<iterations-1) { // do not produce posti
+ siso_algorithm(FSMo.I(),FSMo.S(),FSMo.O(),
+ FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(),
+ blocklength,
+ STo0,SToK,
+ false, true,
+ p2mymin,
+ &(opriori[0]), &(oprioro[0]), &(oposto[0]));
+
+ //interleave soft info outer --> inner
+ for(int k=0;k<blocklength;k++) {
+ int ki = INTERLEAVER.DEINTER()[k];
+ //for(int i=0;i<FSMi.I();i++) {
+ //ipriori[ki*FSMi.I()+i]=oposto[k*FSMi.I()+i];
+ //}
+ memcpy(&(ipriori[ki*FSMi.I()]),&(oposto[k*FSMi.I()]),FSMi.I()*sizeof(float));
+ }
+ }
+ else {// produce posti but not posto
+ siso_algorithm(FSMo.I(),FSMo.S(),FSMo.O(),
+ FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(),
+ blocklength,
+ STo0,SToK,
+ true, false,
+ p2mymin,
+ &(opriori[0]), &(oprioro[0]), &(oposti[0]));
+
+ /*
+ viterbi_algorithm(FSMo.I(),FSMo.S(),FSMo.O(),
+ FSMo.NS(), FSMo.OS(), FSMo.PS(), FSMo.PI(),
+ blocklength,
+ STo0,SToK,
+ &(oprioro[0]), data);
+ */
+ }
+ } // end iterations
+
+ // generate hard decisions
+ for(int k=0;k<blocklength;k++) {
+ float min=INF;
+ int mini=0;
+ for(int i=0;i<FSMo.I();i++) {
+ if(oposti[k*FSMo.I()+i]<min) {
+ min=oposti[k*FSMo.I()+i];
+ mini=i;
+ }
+ }
+ data[k]=(T)mini;
+ }
+ }
+
+ //-------
+
+ template void
+ sccc_decoder<unsigned char>(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ const float *iprioro, unsigned char *data);
+
+ template void
+ sccc_decoder<short>(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ const float *iprioro, short *data);
+
+ template void
+ sccc_decoder<int>(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ const float *iprioro, int *data);
+
+ //====================================================
+
+ template<class T> void
+ pccc_decoder(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ const float *cprioro, T *data)
+ {
+ //allocate space for priori, prioro and posti of FSM1
+ std::vector<float> priori1(blocklength*FSM1.I(),0.0);
+ std::vector<float> prioro1(blocklength*FSM1.O());
+ std::vector<float> posti1(blocklength*FSM1.I());
+
+ //allocate space for priori, prioro and posti of FSM2
+ std::vector<float> priori2(blocklength*FSM2.I(),0.0);
+ std::vector<float> prioro2(blocklength*FSM2.O());
+ std::vector<float> posti2(blocklength*FSM2.I());
+
+ //generate prioro1,2 (metrics are not updated per iteration: this is not the best you can do...)
+ for(int k=0;k<blocklength;k++) {
+ //std::cout << k << std::endl;
+ for(int i=0;i<FSM1.O();i++) {
+ float x=cprioro[k*FSM1.O()*FSM2.O()+i*FSM1.O()+0];
+ for(int j=1;j<FSM2.O();j++)
+ x = (*p2mymin)(x,cprioro[k*FSM1.O()*FSM2.O()+i*FSM1.O()+j]);
+ prioro1[k*FSM1.O()+i]=x;
+ //std::cout << prioro1[k*FSM1.O()+i] << ", ";
+ }
+ //std::cout << std::endl;
+ for(int i=0;i<FSM2.O();i++) {
+ float x=cprioro[k*FSM1.O()*FSM2.O()+0*FSM1.O()+i];
+ for(int j=1;j<FSM1.O();j++)
+ x = (*p2mymin)(x,cprioro[k*FSM1.O()*FSM2.O()+j*FSM1.O()+i]);
+ prioro2[k*FSM2.O()+i]=x;
+ }
+ }
+
+ for(int rep=0;rep<iterations;rep++) {
+ // run SISO 1
+ siso_algorithm(FSM1.I(),FSM1.S(),FSM1.O(),
+ FSM1.NS(), FSM1.OS(), FSM1.PS(), FSM1.PI(),
+ blocklength,
+ ST10,ST1K,
+ true, false,
+ p2mymin,
+ &(priori1[0]), &(prioro1[0]), &(posti1[0]));
+
+ //for(int k=0;k<blocklength;k++){
+ //for(int i=0;i<FSM1.I();i++)
+ //std::cout << posti1[k*FSM1.I()+i] << ", ";
+ //std::cout << std::endl;
+ //}
+
+ //interleave soft info 1 -> 2
+ for(int k=0;k<blocklength;k++) {
+ int ki = INTERLEAVER.INTER()[k];
+ //for(int i=0;i<FSMi.I();i++) {
+ //oprioro[k*FSMi.I()+i]=iposti[ki*FSMi.I()+i];
+ //}
+ memcpy(&(priori2[k*FSM2.I()]),&(posti1[ki*FSM1.I()]),FSM1.I()*sizeof(float));
+ }
+
+ // run SISO 2
+ siso_algorithm(FSM2.I(),FSM2.S(),FSM2.O(),
+ FSM2.NS(), FSM2.OS(), FSM2.PS(), FSM2.PI(),
+ blocklength,
+ ST20,ST2K,
+ true, false,
+ p2mymin,
+ &(priori2[0]), &(prioro2[0]), &(posti2[0]));
+
+ //interleave soft info 2 --> 1
+ for(int k=0;k<blocklength;k++) {
+ int ki = INTERLEAVER.INTER()[k];
+ //for(int i=0;i<FSMi.I();i++) {
+ //ipriori[ki*FSMi.I()+i]=oposto[k*FSMi.I()+i];
+ //}
+ memcpy(&(priori1[ki*FSM1.I()]),&(posti2[k*FSM2.I()]),FSM1.I()*sizeof(float));
+ }
+ } // end iterations
+
+ // generate hard decisions
+ for(int k=0;k<blocklength;k++) {
+ for(int i=0;i<FSM1.I();i++)
+ posti1[k*FSM1.I()+i] = (*p2mymin)(priori1[k*FSM1.I()+i],posti1[k*FSM1.I()+i]);
+ float min=INF;
+ int mini=0;
+ for(int i=0;i<FSM1.I();i++) {
+ if(posti1[k*FSM1.I()+i]<min) {
+ min=posti1[k*FSM1.I()+i];
+ mini=i;
+ }
+ }
+ data[k]=(T)mini;
+ //std::cout << data[k] << ", "<< std::endl;
+ }
+ //std::cout << std::endl;
+ }
+
+ //----------------
+
+ template void
+ pccc_decoder<unsigned char>(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ const float *cprioro, unsigned char *data);
+
+ template void
+ pccc_decoder<short>(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ const float *cprioro, short *data);
+
+ template void
+ pccc_decoder<int>(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ const float *cprioro, int *data);
+
+ //----------------
+
+ template<class Ti, class To> void
+ pccc_decoder_combined(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<Ti> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const Ti *observations, To *data)
+ {
+ //allocate space for cprioro
+ std::vector<float> cprioro(blocklength*FSM1.O()*FSM2.O(),0.0);
+
+ //allocate space for priori, prioro and posti of FSM1
+ std::vector<float> priori1(blocklength*FSM1.I(),0.0);
+ std::vector<float> prioro1(blocklength*FSM1.O());
+ std::vector<float> posti1(blocklength*FSM1.I());
+
+ //allocate space for priori, prioro and posti of FSM2
+ std::vector<float> priori2(blocklength*FSM2.I(),0.0);
+ std::vector<float> prioro2(blocklength*FSM2.O());
+ std::vector<float> posti2(blocklength*FSM2.I());
+
+ // turn observations to neg-log-priors for cprioiro
+ int O=FSM1.O()*FSM2.O();
+ for(int k=0;k<blocklength;k++) {
+ calc_metric(O, D, TABLE, &(observations[k*D]), &(cprioro[k*O]),METRIC_TYPE);
+ cprioro[k*O] *= scaling;
+ }
+
+ //generate prioro1,2 (metrics are not updated per iteration: this is not the best you can do...)
+ for(int k=0;k<blocklength;k++) {
+ //std::cout << k << std::endl;
+ for(int i=0;i<FSM1.O();i++) {
+ float x=cprioro[k*FSM1.O()*FSM2.O()+i*FSM1.O()+0];
+ for(int j=1;j<FSM2.O();j++)
+ x = (*p2mymin)(x,cprioro[k*FSM1.O()*FSM2.O()+i*FSM1.O()+j]);
+ prioro1[k*FSM1.O()+i]=x;
+ //std::cout << prioro1[k*FSM1.O()+i] << ", ";
+ }
+ //std::cout << std::endl;
+ for(int i=0;i<FSM2.O();i++) {
+ float x=cprioro[k*FSM1.O()*FSM2.O()+0*FSM1.O()+i];
+ for(int j=1;j<FSM1.O();j++)
+ x = (*p2mymin)(x,cprioro[k*FSM1.O()*FSM2.O()+j*FSM1.O()+i]);
+ prioro2[k*FSM2.O()+i]=x;
+ }
+ }
+
+ for(int rep=0;rep<iterations;rep++) {
+ // run SISO 1
+ siso_algorithm(FSM1.I(),FSM1.S(),FSM1.O(),
+ FSM1.NS(), FSM1.OS(), FSM1.PS(), FSM1.PI(),
+ blocklength,
+ ST10,ST1K,
+ true, false,
+ p2mymin,
+ &(priori1[0]), &(prioro1[0]), &(posti1[0]));
+
+ //for(int k=0;k<blocklength;k++){
+ //for(int i=0;i<FSM1.I();i++)
+ //std::cout << posti1[k*FSM1.I()+i] << ", ";
+ //std::cout << std::endl;
+ //}
+
+ //interleave soft info 1 -> 2
+ for(int k=0;k<blocklength;k++) {
+ int ki = INTERLEAVER.INTER()[k];
+ //for(int i=0;i<FSMi.I();i++) {
+ //oprioro[k*FSMi.I()+i]=iposti[ki*FSMi.I()+i];
+ //}
+ memcpy(&(priori2[k*FSM2.I()]),&(posti1[ki*FSM1.I()]),FSM1.I()*sizeof(float));
+ }
+
+ // run SISO 2
+ siso_algorithm(FSM2.I(),FSM2.S(),FSM2.O(),
+ FSM2.NS(), FSM2.OS(), FSM2.PS(), FSM2.PI(),
+ blocklength,
+ ST20,ST2K,
+ true, false,
+ p2mymin,
+ &(priori2[0]), &(prioro2[0]), &(posti2[0]));
+
+ //interleave soft info 2 --> 1
+ for(int k=0;k<blocklength;k++) {
+ int ki = INTERLEAVER.INTER()[k];
+ //for(int i=0;i<FSMi.I();i++) {
+ //ipriori[ki*FSMi.I()+i]=oposto[k*FSMi.I()+i];
+ //}
+ memcpy(&(priori1[ki*FSM1.I()]),&(posti2[k*FSM2.I()]),FSM1.I()*sizeof(float));
+ }
+ } // end iterations
+
+ // generate hard decisions
+ for(int k=0;k<blocklength;k++) {
+ for(int i=0;i<FSM1.I();i++)
+ posti1[k*FSM1.I()+i] = (*p2mymin)(priori1[k*FSM1.I()+i],posti1[k*FSM1.I()+i]);
+ float min=INF;
+ int mini=0;
+ for(int i=0;i<FSM1.I();i++) {
+ if(posti1[k*FSM1.I()+i]<min) {
+ min=posti1[k*FSM1.I()+i];
+ mini=i;
+ }
+ }
+ data[k]=(To)mini;
+ //std::cout << data[k] << ", "<< std::endl;
+ }
+ //std::cout << std::endl;
+ }
+
+ template void
+ pccc_decoder_combined(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const float *observations, unsigned char *data);
+
+ template void
+ pccc_decoder_combined(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const float *observations, short *data);
+
+ template void
+ pccc_decoder_combined(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const float *observations, int *data);
+
+ template void
+ pccc_decoder_combined(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<gr_complex> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const gr_complex *observations, unsigned char *data);
+
+ template void
+ pccc_decoder_combined(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<gr_complex> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const gr_complex *observations, short *data);
+
+ template void
+ pccc_decoder_combined(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER, int blocklength,
+ int iterations,
+ float (*p2mymin)(float,float),
+ int D, const std::vector<gr_complex> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling,
+ const gr_complex *observations, int *data);
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/encoder_XX_impl.cc.t b/gr-trellis/lib/encoder_XX_impl.cc.t
new file mode 100644
index 0000000000..fdda593d45
--- /dev/null
+++ b/gr-trellis/lib/encoder_XX_impl.cc.t
@@ -0,0 +1,82 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "@NAME@.h"
+#include <gr_io_signature.h>
+#include <iostream>
+
+namespace gr {
+ namespace trellis {
+
+ @BASE_NAME@::sptr
+ @BASE_NAME@::make(const fsm &FSM, int ST)
+ {
+ return gnuradio::get_initial_sptr
+ (new @IMPL_NAME@(FSM,ST));
+ }
+
+ @IMPL_NAME@::@IMPL_NAME@(const fsm &FSM, int ST)
+ : gr_sync_block("@BASE_NAME@",
+ gr_make_io_signature(1, -1, sizeof(@I_TYPE@)),
+ gr_make_io_signature(1, -1, sizeof(@O_TYPE@))),
+ d_FSM(FSM),
+ d_ST(ST)
+ {
+ }
+
+ @IMPL_NAME@::~@IMPL_NAME@()
+ {
+ }
+
+ int
+ @IMPL_NAME@::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int ST_tmp = 0;
+ int nstreams = input_items.size();
+
+ for(int m=0;m<nstreams;m++) {
+ const @I_TYPE@ *in = (const @I_TYPE@*)input_items[m];
+ @O_TYPE@ *out = (@O_TYPE@ *) output_items[m];
+ ST_tmp = d_ST;
+
+ // per stream processing
+ for(int i = 0; i < noutput_items; i++) {
+ out[i] = (@O_TYPE@)d_FSM.OS()[ST_tmp*d_FSM.I()+in[i]]; // direction of time?
+ ST_tmp = (int)d_FSM.NS()[ST_tmp*d_FSM.I()+in[i]];
+ }
+ // end per stream processing
+ }
+ d_ST = ST_tmp;
+
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/encoder_XX_impl.h.t b/gr-trellis/lib/encoder_XX_impl.h.t
new file mode 100644
index 0000000000..949f1182de
--- /dev/null
+++ b/gr-trellis/lib/encoder_XX_impl.h.t
@@ -0,0 +1,54 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifndef @GUARD_NAME@
+#define @GUARD_NAME@
+
+#include <trellis/@BASE_NAME@.h>
+
+namespace gr {
+ namespace trellis {
+
+ class @IMPL_NAME@ : public @BASE_NAME@
+ {
+ private:
+ fsm d_FSM;
+ int d_ST;
+
+ public:
+ @IMPL_NAME@(const fsm &FSM, int ST);
+ ~@IMPL_NAME@();
+
+ fsm FSM() const { return d_FSM; }
+ int ST() const { return d_ST; }
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* @GUARD_NAME@ */
diff --git a/gr-trellis/lib/fsm.cc b/gr-trellis/lib/fsm.cc
new file mode 100644
index 0000000000..16efcd10f2
--- /dev/null
+++ b/gr-trellis/lib/fsm.cc
@@ -0,0 +1,521 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2002,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <cstdio>
+#include <string>
+#include <iostream>
+#include <fstream>
+#include <stdexcept>
+#include <cmath>
+#include <stdlib.h>
+#include <trellis/base.h>
+#include <trellis/fsm.h>
+
+namespace gr {
+ namespace trellis {
+
+ fsm::fsm()
+ {
+ d_I=0;
+ d_S=0;
+ d_O=0;
+ d_NS.resize(0);
+ d_OS.resize(0);
+ d_PS.resize(0);
+ d_PI.resize(0);
+ d_TMi.resize(0);
+ d_TMl.resize(0);
+ }
+
+ fsm::fsm(const fsm &FSM)
+ {
+ d_I=FSM.I();
+ d_S=FSM.S();
+ d_O=FSM.O();
+ d_NS=FSM.NS();
+ d_OS=FSM.OS();
+ d_PS=FSM.PS(); // is this going to make a deep copy?
+ d_PI=FSM.PI();
+ d_TMi=FSM.TMi();
+ d_TMl=FSM.TMl();
+ }
+
+ fsm::fsm(int I, int S, int O, const std::vector<int> &NS, const std::vector<int> &OS)
+ {
+ d_I=I;
+ d_S=S;
+ d_O=O;
+ d_NS=NS;
+ d_OS=OS;
+
+ generate_PS_PI();
+ generate_TM();
+ }
+
+ //######################################################################
+ //# Read an FSM specification from a file.
+ //# Format (hopefully will become more flexible in the future...):
+ //# I S O (in the first line)
+ //# blank line
+ //# Next state matrix (S lines, each with I integers separated by spaces)
+ //# blank line
+ //# output symbol matrix (S lines, each with I integers separated by spaces)
+ //# optional comments
+ //######################################################################
+ fsm::fsm(const char *name)
+ {
+ FILE *fsmfile;
+
+ if((fsmfile=fopen(name,"r"))==NULL)
+ throw std::runtime_error ("fsm::fsm(const char *name): file open error\n");
+ //printf("file open error in fsm()\n");
+
+ if(fscanf(fsmfile,"%d %d %d\n",&d_I,&d_S,&d_O) == EOF) {
+ if(ferror(fsmfile) != 0)
+ throw std::runtime_error ("fsm::fsm(const char *name): file read error\n");
+ }
+
+ d_NS.resize(d_I*d_S);
+ d_OS.resize(d_I*d_S);
+
+ for(int i=0;i<d_S;i++) {
+ for(int j=0;j<d_I;j++) {
+ if(fscanf(fsmfile,"%d",&(d_NS[i*d_I+j])) == EOF) {
+ if(ferror(fsmfile) != 0)
+ throw std::runtime_error ("fsm::fsm(const char *name): file read error\n");
+ }
+ }
+ }
+ for(int i=0;i<d_S;i++) {
+ for(int j=0;j<d_I;j++) {
+ if(fscanf(fsmfile,"%d",&(d_OS[i*d_I+j])) == EOF) {
+ if(ferror(fsmfile) != 0)
+ throw std::runtime_error ("fsm::fsm(const char *name): file read error\n");
+ }
+ }
+ }
+
+ fclose(fsmfile);
+
+ generate_PS_PI();
+ generate_TM();
+ }
+
+ //######################################################################
+ //# Automatically generate the FSM from the generator matrix
+ //# of a (n,k) binary convolutional code
+ //######################################################################
+ fsm::fsm(int k, int n, const std::vector<int> &G)
+ {
+ // calculate maximum memory requirements for each input stream
+ std::vector<int> max_mem_x(k,-1);
+ int max_mem = -1;
+ for(int i=0;i<k;i++) {
+ for(int j=0;j<n;j++) {
+ int mem = -1;
+ if(G[i*n+j]!=0)
+ mem=(int)(log(double(G[i*n+j]))/log(2.0));
+ if(mem>max_mem_x[i])
+ max_mem_x[i]=mem;
+ if(mem>max_mem)
+ max_mem=mem;
+ }
+ }
+
+ //printf("max_mem_x\n");
+ //for(int j=0;j<max_mem_x.size();j++) printf("%d ",max_mem_x[j]); printf("\n");
+
+ // calculate total memory requirements to set S
+ int sum_max_mem = 0;
+ for(int i=0;i<k;i++)
+ sum_max_mem += max_mem_x[i];
+
+ //printf("sum_max_mem = %d\n",sum_max_mem);
+
+ d_I=1<<k;
+ d_S=1<<sum_max_mem;
+ d_O=1<<n;
+
+ // binary representation of the G matrix
+ std::vector<std::vector<int> > Gb(k*n);
+ for(int j=0;j<k*n;j++) {
+ Gb[j].resize(max_mem+1);
+ dec2base(G[j],2,Gb[j]);
+ //printf("Gb\n");
+ //for(int m=0;m<Gb[j].size();m++) printf("%d ",Gb[j][m]); printf("\n");
+ }
+
+ // alphabet size of each shift register
+ std::vector<int> bases_x(k);
+ for(int j=0;j<k ;j++)
+ bases_x[j] = 1 << max_mem_x[j];
+ //printf("bases_x\n");
+ //for(int j=0;j<max_mem_x.size();j++) printf("%d ",max_mem_x[j]); printf("\n");
+
+ d_NS.resize(d_I*d_S);
+ d_OS.resize(d_I*d_S);
+
+ std::vector<int> sx(k);
+ std::vector<int> nsx(k);
+ std::vector<int> tx(k);
+ std::vector<std::vector<int> > tb(k);
+ for(int j=0;j<k;j++)
+ tb[j].resize(max_mem+1);
+ std::vector<int> inb(k);
+ std::vector<int> outb(n);
+
+ for(int s=0;s<d_S;s++) {
+ dec2bases(s,bases_x,sx); // split s into k values, each representing one of the k shift registers
+ //printf("state = %d \nstates = ",s);
+ //for(int j=0;j<sx.size();j++) printf("%d ",sx[j]); printf("\n");
+ for(int i=0;i<d_I;i++) {
+ dec2base(i,2,inb); // input in binary
+ //printf("input = %d \ninputs = ",i);
+ //for(int j=0;j<inb.size();j++) printf("%d ",inb[j]); printf("\n");
+
+ // evaluate next state
+ for(int j=0;j<k;j++)
+ nsx[j] = (inb[j]*bases_x[j]+sx[j])/2; // next state (for each shift register) MSB first
+ d_NS[s*d_I+i]=bases2dec(nsx,bases_x); // collect all values into the new state
+
+ // evaluate transitions
+ for(int j=0;j<k;j++)
+ tx[j] = inb[j]*bases_x[j]+sx[j]; // transition (for each shift register)MSB first
+ for(int j=0;j<k;j++) {
+ dec2base(tx[j],2,tb[j]); // transition in binary
+ //printf("transition = %d \ntransitions = ",tx[j]);
+ //for(int m=0;m<tb[j].size();m++) printf("%d ",tb[j][m]); printf("\n");
+ }
+
+ // evaluate outputs
+ for(int nn=0;nn<n;nn++) {
+ outb[nn] = 0;
+ for(int j=0;j<k;j++) {
+ for(int m=0;m<max_mem+1;m++)
+ outb[nn] = (outb[nn] + Gb[j*n+nn][m]*tb[j][m]) % 2; // careful: polynomial 1+D ir represented as 110, not as 011
+ //printf("output %d equals %d\n",nn,outb[nn]);
+ }
+ }
+ d_OS[s*d_I+i] = base2dec(outb,2);
+ }
+ }
+
+ generate_PS_PI();
+ generate_TM();
+ }
+
+ //######################################################################
+ //# Automatically generate an FSM specification describing the
+ //# ISI for a channel
+ //# of length ch_length and a modulation of size mod_size
+ //######################################################################
+ fsm::fsm(int mod_size, int ch_length)
+ {
+ d_I=mod_size;
+ d_S=(int) (pow(1.0*d_I,1.0*ch_length-1)+0.5);
+ d_O=d_S*d_I;
+
+ d_NS.resize(d_I*d_S);
+ d_OS.resize(d_I*d_S);
+
+ for(int s=0;s<d_S;s++) {
+ for(int i=0;i<d_I;i++) {
+ int t=i*d_S+s;
+ d_NS[s*d_I+i] = t/d_I;
+ d_OS[s*d_I+i] = t;
+ }
+ }
+
+ generate_PS_PI();
+ generate_TM();
+ }
+
+ //######################################################################
+ //# Automatically generate an FSM specification describing the
+ //# the trellis for a CPM with h=K/P (relatively prime),
+ //# alphabet size M, and frequency pulse duration L symbols
+ //#
+ //# This FSM is based on the paper by B. Rimoldi
+ //# "A decomposition approach to CPM", IEEE Trans. Info Theory, March 1988
+ //# See also my own notes at http://www.eecs.umich.edu/~anastas/docs/cpm.pdf
+ //######################################################################
+ fsm::fsm(int P, int M, int L)
+ {
+ d_I=M;
+ d_S=(int)(pow(1.0*M,1.0*L-1)+0.5)*P;
+ d_O=(int)(pow(1.0*M,1.0*L)+0.5)*P;
+
+ d_NS.resize(d_I*d_S);
+ d_OS.resize(d_I*d_S);
+ int nv;
+ for(int s=0;s<d_S;s++) {
+ for(int i=0;i<d_I;i++) {
+ int s1=s/P;
+ int v=s%P;
+ int ns1= (i*(int)(pow(1.0*M,1.0*(L-1))+0.5)+s1)/M;
+ if (L==1)
+ nv=(i+v)%P;
+ else
+ nv=(s1%M+v)%P;
+ d_NS[s*d_I+i] = ns1*P+nv;
+ d_OS[s*d_I+i] = i*d_S+s;
+ }
+ }
+
+ generate_PS_PI();
+ generate_TM();
+ }
+
+ //######################################################################
+ //# Automatically generate an FSM specification describing the
+ //# the joint trellis of fsm1 and fsm2
+ //######################################################################
+ fsm::fsm(const fsm &FSM1, const fsm &FSM2)
+ {
+ d_I=FSM1.I()*FSM2.I();
+ d_S=FSM1.S()*FSM2.S();
+ d_O=FSM1.O()*FSM2.O();
+
+ d_NS.resize(d_I*d_S);
+ d_OS.resize(d_I*d_S);
+
+ for(int s=0;s<d_S;s++) {
+ for(int i=0;i<d_I;i++) {
+ int s1=s/FSM2.S();
+ int s2=s%FSM2.S();
+ int i1=i/FSM2.I();
+ int i2=i%FSM2.I();
+ d_NS[s*d_I+i] = FSM1.NS()[s1 * FSM1.I() + i1] * FSM2.S() + FSM2.NS()[s2 * FSM2.I() + i2];
+ d_OS[s*d_I+i] = FSM1.OS()[s1 * FSM1.I() + i1] * FSM2.O() + FSM2.OS()[s2 * FSM2.I() + i2];
+ }
+ }
+
+ generate_PS_PI();
+ generate_TM();
+ }
+
+ //######################################################################
+ //# Generate a new FSM representing n stages through the original FSM
+ //# AKA radix-n FSM
+ //######################################################################
+ fsm::fsm(const fsm &FSM, int n)
+ {
+ d_I=(int) (pow(1.0*FSM.I(),1.0*n)+0.5);
+ d_S=FSM.S();
+ d_O=(int) (pow(1.0*FSM.O(),1.0*n)+0.5);
+
+ d_NS.resize(d_I*d_S);
+ d_OS.resize(d_I*d_S);
+
+ for(int s=0;s<d_S;s++ ) {
+ for(int i=0;i<d_I;i++ ) {
+ std::vector<int> ii(n);
+ dec2base(i,FSM.I(),ii);
+ std::vector<int> oo(n);
+ int ns=s;
+ for(int k=0;k<n;k++) {
+ oo[k]=FSM.OS()[ns*FSM.I()+ii[k]];
+ ns=FSM.NS()[ns*FSM.I()+ii[k]];
+ }
+ d_NS[s*d_I+i]=ns;
+ d_OS[s*d_I+i]=base2dec(oo,FSM.O());
+ }
+ }
+
+ generate_PS_PI();
+ generate_TM();
+ }
+
+ //######################################################################
+ //# generate the PS and PI tables for later use
+ //######################################################################
+ void
+ fsm::generate_PS_PI()
+ {
+ d_PS.resize(d_S);
+ d_PI.resize(d_S);
+
+ for(int i=0;i<d_S;i++) {
+ d_PS[i].resize(d_I*d_S); // max possible size
+ d_PI[i].resize(d_I*d_S);
+ int j=0;
+ for(int ii=0;ii<d_S;ii++) for(int jj=0;jj<d_I;jj++) {
+ if(d_NS[ii*d_I+jj]!=i) continue;
+ d_PS[i][j]=ii;
+ d_PI[i][j]=jj;
+ j++;
+ }
+ d_PS[i].resize(j);
+ d_PI[i].resize(j);
+ }
+ }
+
+ //######################################################################
+ //# generate the termination matrices TMl and TMi for later use
+ //######################################################################
+ void
+ fsm::generate_TM()
+ {
+ d_TMi.resize(d_S*d_S);
+ d_TMl.resize(d_S*d_S);
+
+ for(int i=0;i<d_S*d_S;i++) {
+ d_TMi[i] = -1; // no meaning
+ d_TMl[i] = d_S; //infinity: you need at most S-1 steps
+ if (i/d_S == i%d_S)
+ d_TMl[i] = 0;
+ }
+
+ for(int s=0;s<d_S;s++) {
+ bool done = false;
+ int attempts = 0;
+ while (done == false && attempts < d_S-1) {
+ done = find_es(s);
+ attempts ++;
+ }
+ if (done == false && d_S > 1) {
+ //throw std::runtime_error ("fsm::generate_TM(): FSM appears to be disconnected\n");
+ printf("fsm::generate_TM(): FSM appears to be disconnected\n");
+ printf("state %d cannot be reached from all other states\n",s);
+ }
+ }
+ }
+
+ // find a path from any state to the ending state "es"
+ bool
+ fsm::find_es(int es)
+ {
+ bool done = true;
+ for(int s=0;s<d_S;s++) {
+ if(d_TMl[s*d_S+es] < d_S)
+ continue;
+ int minl=d_S;
+ int mini=-1;
+ for(int i=0;i<d_I;i++) {
+ if( 1 + d_TMl[d_NS[s*d_I+i]*d_S+es] < minl) {
+ minl = 1 + d_TMl[d_NS[s*d_I+i]*d_S+es];
+ mini = i;
+ }
+ }
+ if (mini != -1) {
+ d_TMl[s*d_S+es]=minl;
+ d_TMi[s*d_S+es]=mini;
+ }
+ else
+ done = false;
+ }
+ return done;
+ }
+
+ //######################################################################
+ //# generate trellis representation of FSM as an SVG file
+ //######################################################################
+ void
+ fsm::write_trellis_svg(std::string filename, int number_stages)
+ {
+ std::ofstream trellis_fname (filename.c_str());
+ if(!trellis_fname) {
+ std::cout << "file not found " << std::endl ; exit(-1);
+ }
+ const int TRELLIS_Y_OFFSET = 30;
+ const int TRELLIS_X_OFFSET = 20;
+ const int STAGE_LABEL_Y_OFFSET = 25;
+ const int STAGE_LABEL_X_OFFSET = 20;
+ const int STATE_LABEL_Y_OFFSET = 30;
+ const int STATE_LABEL_X_OFFSET = 5;
+ const int STAGE_STATE_OFFSETS = 10;
+ // std::cout << "################## BEGIN SVG TRELLIS PIC #####################" << std::endl;
+ trellis_fname << "<svg viewBox = \"0 0 200 200\" version = \"1.1\">" << std::endl;
+
+ for(int stage_num = 0;stage_num < number_stages;stage_num ++) {
+ // draw states
+ for(int state_num = 0;state_num < d_S ; state_num ++ ) {
+ trellis_fname << "<circle cx = \"" << stage_num * STAGE_STATE_OFFSETS + TRELLIS_X_OFFSET <<
+ "\" cy = \"" << state_num * STAGE_STATE_OFFSETS + TRELLIS_Y_OFFSET << "\" r = \"1\"/>" << std::endl;
+ //draw branches
+ if(stage_num != number_stages-1) {
+ for(int branch_num = 0;branch_num < d_I; branch_num++) {
+ trellis_fname << "<line x1 =\"" << STAGE_STATE_OFFSETS * stage_num+ TRELLIS_X_OFFSET << "\" ";
+ trellis_fname << "y1 =\"" << state_num * STAGE_STATE_OFFSETS + TRELLIS_Y_OFFSET<< "\" ";
+ trellis_fname << "x2 =\"" << STAGE_STATE_OFFSETS *stage_num + STAGE_STATE_OFFSETS+ TRELLIS_X_OFFSET << "\" ";
+ trellis_fname << "y2 =\"" << d_NS[d_I * state_num + branch_num] * STAGE_STATE_OFFSETS + TRELLIS_Y_OFFSET << "\" ";
+ trellis_fname << " stroke-dasharray = \"3," << branch_num << "\" ";
+ trellis_fname << " stroke = \"black\" stroke-width = \"0.3\"/>" << std::endl;
+ }
+ }
+ }
+ }
+ // label the stages
+ trellis_fname << "<g font-size = \"4\" font= \"times\" fill = \"black\">" << std::endl;
+ for(int stage_num = 0;stage_num < number_stages ;stage_num ++) {
+ trellis_fname << "<text x = \"" << stage_num * STAGE_STATE_OFFSETS + STAGE_LABEL_X_OFFSET <<
+ "\" y = \"" << STAGE_LABEL_Y_OFFSET << "\" >" << std::endl;
+ trellis_fname << stage_num << std::endl;
+ trellis_fname << "</text>" << std::endl;
+ }
+ trellis_fname << "</g>" << std::endl;
+
+ // label the states
+ trellis_fname << "<g font-size = \"4\" font= \"times\" fill = \"black\">" << std::endl;
+ for(int state_num = 0;state_num < d_S ; state_num ++) {
+ trellis_fname << "<text y = \"" << state_num * STAGE_STATE_OFFSETS + STATE_LABEL_Y_OFFSET <<
+ "\" x = \"" << STATE_LABEL_X_OFFSET << "\" >" << std::endl;
+ trellis_fname << state_num << std::endl;
+ trellis_fname << "</text>" << std::endl;
+ }
+ trellis_fname << "</g>" << std::endl;
+
+ trellis_fname << "</svg>" << std::endl;
+ // std::cout << "################## END SVG TRELLIS PIC ##################### " << std::endl;
+ trellis_fname.close();
+ }
+
+ //######################################################################
+ //# Write trellis specification to a text file,
+ //# in the same format used when reading FSM files
+ //######################################################################
+ void
+ fsm::write_fsm_txt(std::string filename)
+ {
+ std::ofstream trellis_fname (filename.c_str());
+ if(!trellis_fname) {
+ std::cout << "file not found " << std::endl ; exit(-1);
+ }
+ trellis_fname << d_I << ' ' << d_S << ' ' << d_O << std::endl;
+ trellis_fname << std::endl;
+ for(int i=0;i<d_S;i++) {
+ for(int j=0;j<d_I;j++)
+ trellis_fname << d_NS[i*d_I+j] << ' ';
+ trellis_fname << std::endl;
+ }
+ trellis_fname << std::endl;
+ for(int i=0;i<d_S;i++) {
+ for(int j=0;j<d_I;j++)
+ trellis_fname << d_OS[i*d_I+j] << ' ';
+ trellis_fname << std::endl;
+ }
+ trellis_fname << std::endl;
+ trellis_fname.close();
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/interleaver.cc b/gr-trellis/lib/interleaver.cc
new file mode 100644
index 0000000000..27248a6d43
--- /dev/null
+++ b/gr-trellis/lib/interleaver.cc
@@ -0,0 +1,147 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2002,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <cstdlib>
+#include <cstdio>
+#include <iostream>
+#include <string>
+#include <fstream>
+#include <stdexcept>
+#include <cmath>
+#include <trellis/quicksort_index.h>
+#include <trellis/interleaver.h>
+
+namespace gr {
+ namespace trellis {
+
+ interleaver::interleaver()
+ {
+ d_K=0;
+ d_INTER.resize(0);
+ d_DEINTER.resize(0);
+ }
+
+ interleaver::interleaver(const interleaver &INTERLEAVER)
+ {
+ d_K=INTERLEAVER.K();
+ d_INTER=INTERLEAVER.INTER();
+ d_DEINTER=INTERLEAVER.DEINTER();
+ }
+
+ interleaver::interleaver(int K, const std::vector<int> &INTER)
+ {
+ d_K=K;
+ d_INTER=INTER;
+ d_DEINTER.resize(d_K);
+
+ // generate DEINTER table
+ for(int i=0;i<d_K;i++) {
+ d_DEINTER[d_INTER[i]]=i;
+ }
+ }
+
+ //######################################################################
+ //# Read an INTERLEAVER specification from a file.
+ //# Format (hopefully will become more flexible in the future...):
+ //# K
+ //# blank line
+ //# list of space separated K integers from 0 to K-1 in appropriate order
+ //# optional comments
+ //######################################################################
+ interleaver::interleaver(const char *name)
+ {
+ FILE *interleaverfile;
+
+ if((interleaverfile=fopen(name,"r")) == NULL)
+ throw std::runtime_error ("file open error in interleaver()");
+ //printf("file open error in interleaver()\n");
+
+ if(fscanf(interleaverfile,"%d\n",&d_K) == EOF) {
+ if(ferror(interleaverfile) != 0)
+ throw std::runtime_error ("interleaver::interleaver(const char *name): file read error\n");
+ }
+
+ d_INTER.resize(d_K);
+ d_DEINTER.resize(d_K);
+
+ for(int i=0;i<d_K;i++) {
+ if(fscanf(interleaverfile,"%d",&(d_INTER[i])) == EOF) {
+ if(ferror(interleaverfile) != 0)
+ throw std::runtime_error("interleaver::interleaver(const char *name): file read error\n");
+ }
+ }
+
+ // generate DEINTER table
+ for(int i=0;i<d_K;i++) {
+ d_DEINTER[d_INTER[i]]=i;
+ }
+ }
+
+ //######################################################################
+ //# Generate a random interleaver
+ //######################################################################
+ interleaver::interleaver(int K, int seed)
+ {
+ d_K=K;
+ d_INTER.resize(d_K);
+ d_DEINTER.resize(d_K);
+
+ if(seed>=0)
+ srand((unsigned int)seed);
+ std::vector<int> tmp(d_K);
+ for(int i=0;i<d_K;i++) {
+ d_INTER[i]=i;
+ tmp[i] = rand();
+ }
+ quicksort_index <int> (tmp,d_INTER,0,d_K-1);
+
+ // generate DEINTER table
+ for(int i=0;i<d_K;i++) {
+ d_DEINTER[d_INTER[i]]=i;
+ }
+ }
+
+ //######################################################################
+ //# Write an INTERLEAVER specification to a file.
+ //# Format
+ //# K
+ //# blank line
+ //# list of space separated K integers from 0 to K-1 in appropriate order
+ //# optional comments
+ //######################################################################
+ void
+ interleaver::write_interleaver_txt(std::string filename)
+ {
+ std::ofstream interleaver_fname (filename.c_str());
+ if(!interleaver_fname) {
+ std::cout << "file not found " << std::endl ; exit(-1);
+ }
+ interleaver_fname << d_K << std::endl;
+ interleaver_fname << std::endl;
+ for(int i=0;i<d_K;i++)
+ interleaver_fname << d_INTER[i] << ' ';
+ interleaver_fname << std::endl;
+ interleaver_fname.close();
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/metrics_X_impl.cc.t b/gr-trellis/lib/metrics_X_impl.cc.t
new file mode 100644
index 0000000000..c74051c53e
--- /dev/null
+++ b/gr-trellis/lib/metrics_X_impl.cc.t
@@ -0,0 +1,98 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "@NAME@.h"
+#include <gr_io_signature.h>
+#include <assert.h>
+#include <stdexcept>
+#include <iostream>
+
+namespace gr {
+ namespace trellis {
+
+ @BASE_NAME@::sptr
+ @BASE_NAME@::make(int O, int D, const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t TYPE)
+ {
+ return gnuradio::get_initial_sptr
+ (new @IMPL_NAME@(O,D,TABLE,TYPE));
+ }
+
+ @IMPL_NAME@::@IMPL_NAME@(int O, int D, const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t TYPE)
+ : gr_block("@BASE_NAME@",
+ gr_make_io_signature(1, -1, sizeof (@I_TYPE@)),
+ gr_make_io_signature(1, -1, sizeof (float))),
+ d_O(O), d_D(D), d_TYPE(TYPE), d_TABLE(TABLE)
+ {
+ set_relative_rate (1.0 * d_O / ((double) d_D));
+ set_output_multiple ((int)d_O);
+ }
+
+ @IMPL_NAME@::~@IMPL_NAME@()
+ {
+ }
+
+ void
+ @IMPL_NAME@::set_TABLE(const std::vector<@I_TYPE@> &table)
+ {
+ d_TABLE = table;
+ }
+
+ void
+ @IMPL_NAME@::forecast(int noutput_items, gr_vector_int &ninput_items_required)
+ {
+ int input_required = d_D * noutput_items / d_O;
+ unsigned ninputs = ninput_items_required.size();
+ for(unsigned int i = 0; i < ninputs; i++)
+ ninput_items_required[i] = input_required;
+ }
+
+ int
+ @IMPL_NAME@::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int nstreams = input_items.size();
+
+ for(int m = 0; m < nstreams; m++) {
+ const @I_TYPE@ *in = (@I_TYPE@*)input_items[m];
+ float *out = (float*)output_items[m];
+
+ for(int i = 0; i < noutput_items / d_O ; i++) {
+ calc_metric(d_O, d_D, d_TABLE,&(in[i*d_D]), &(out[i*d_O]), d_TYPE);
+ }
+ }
+
+ consume_each(d_D * noutput_items / d_O);
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/metrics_X_impl.h.t b/gr-trellis/lib/metrics_X_impl.h.t
new file mode 100644
index 0000000000..0f52a8bc40
--- /dev/null
+++ b/gr-trellis/lib/metrics_X_impl.h.t
@@ -0,0 +1,64 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifndef @GUARD_NAME@
+#define @GUARD_NAME@
+
+#include <trellis/@BASE_NAME@.h>
+
+namespace gr {
+ namespace trellis {
+
+ class @IMPL_NAME@ : public @BASE_NAME@
+ {
+ private:
+ int d_O;
+ int d_D;
+ digital::trellis_metric_type_t d_TYPE;
+ std::vector<@I_TYPE@> d_TABLE;
+
+ public:
+ @IMPL_NAME@(int O, int D, const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t TYPE);
+ ~@IMPL_NAME@();
+
+ int O() const { return d_O; }
+ int D() const { return d_D; }
+ digital::trellis_metric_type_t TYPE() const { return d_TYPE; }
+ std::vector<@I_TYPE@> TABLE() const { return d_TABLE; }
+ void set_TABLE(const std::vector<@I_TYPE@> &table);
+
+ 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);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* @GUARD_NAME@ */
diff --git a/gr-trellis/lib/pccc_decoder_X_impl.cc.t b/gr-trellis/lib/pccc_decoder_X_impl.cc.t
new file mode 100644
index 0000000000..9bf85bc614
--- /dev/null
+++ b/gr-trellis/lib/pccc_decoder_X_impl.cc.t
@@ -0,0 +1,120 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "@NAME@.h"
+#include <gr_io_signature.h>
+#include <iostream>
+#include <trellis/core_algorithms.h>
+
+namespace gr {
+ namespace trellis {
+
+ static const float INF = 1.0e9;
+
+ @BASE_NAME@::sptr
+ @BASE_NAME@::make(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE)
+ {
+ return gnuradio::get_initial_sptr
+ (new @IMPL_NAME@(FSM1, ST10, ST1K,
+ FSM2, ST20, ST2K,
+ INTERLEAVER,
+ blocklength,
+ repetitions,
+ SISO_TYPE));
+ }
+
+ @IMPL_NAME@::@IMPL_NAME@(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE)
+ : gr_block("@BASE_NAME@",
+ gr_make_io_signature(1, 1, sizeof(float)),
+ gr_make_io_signature(1, 1, sizeof(@O_TYPE@))),
+ d_FSM1(FSM1), d_ST10(ST10), d_ST1K(ST1K),
+ d_FSM2(FSM2), d_ST20(ST20), d_ST2K(ST2K),
+ d_INTERLEAVER(INTERLEAVER),
+ d_blocklength(blocklength),
+ d_repetitions(repetitions),
+ d_SISO_TYPE(SISO_TYPE)
+ {
+ set_relative_rate (1.0 / ((double) d_FSM1.O() * d_FSM2.O()));
+ set_output_multiple (d_blocklength);
+ }
+
+ @IMPL_NAME@::~@IMPL_NAME@()
+ {
+ }
+
+ void
+ @IMPL_NAME@::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ int input_required = d_FSM1.O() * d_FSM2.O() * noutput_items;
+ ninput_items_required[0] = input_required;
+ }
+
+ //===========================================================
+
+ int
+ @IMPL_NAME@::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int nblocks = noutput_items / d_blocklength;
+
+ float (*p2min)(float, float) = NULL;
+ if(d_SISO_TYPE == TRELLIS_MIN_SUM)
+ p2min = &min;
+ else if(d_SISO_TYPE == TRELLIS_SUM_PRODUCT)
+ p2min = &min_star;
+
+ const float *in = (const float *) input_items[0];
+ @O_TYPE@ *out = (@O_TYPE@ *) output_items[0];
+ for(int n=0;n<nblocks;n++) {
+ pccc_decoder(d_FSM1, d_ST10, d_ST1K,
+ d_FSM2, d_ST20, d_ST2K,
+ d_INTERLEAVER, d_blocklength, d_repetitions,
+ p2min,
+ &(in[n*d_blocklength*d_FSM1.O()*d_FSM2.O()]),
+ &(out[n*d_blocklength]));
+ }
+
+ consume_each(d_FSM1.O() * d_FSM2.O() * noutput_items);
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/pccc_decoder_X_impl.h.t b/gr-trellis/lib/pccc_decoder_X_impl.h.t
new file mode 100644
index 0000000000..9b61e34fde
--- /dev/null
+++ b/gr-trellis/lib/pccc_decoder_X_impl.h.t
@@ -0,0 +1,80 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifndef @GUARD_NAME@
+#define @GUARD_NAME@
+
+#include <trellis/@BASE_NAME@.h>
+
+namespace gr {
+ namespace trellis {
+
+ class @IMPL_NAME@ : public @BASE_NAME@
+ {
+ private:
+ fsm d_FSM1;
+ int d_ST10;
+ int d_ST1K;
+ fsm d_FSM2;
+ int d_ST20;
+ int d_ST2K;
+ interleaver d_INTERLEAVER;
+ int d_blocklength;
+ int d_repetitions;
+ siso_type_t d_SISO_TYPE;
+ std::vector<float> d_buffer;
+
+ public:
+ @IMPL_NAME@(const fsm &FSM1, int ST10, int ST1K,
+ const fsm &FSM2, int ST20, int ST2K,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE);
+ ~@IMPL_NAME@();
+
+ fsm FSM1() const { return d_FSM1; }
+ fsm FSM2() const { return d_FSM2; }
+ int ST10() const { return d_ST10; }
+ int ST1K() const { return d_ST1K; }
+ int ST20() const { return d_ST20; }
+ int ST2K() const { return d_ST2K; }
+ interleaver INTERLEAVER() const { return d_INTERLEAVER; }
+ int blocklength() const { return d_blocklength; }
+ int repetitions() const { return d_repetitions; }
+ siso_type_t SISO_TYPE() const { return d_SISO_TYPE; }
+
+ 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);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* @GUARD_NAME@ */
diff --git a/gr-trellis/lib/pccc_decoder_combined_XX_impl.cc.t b/gr-trellis/lib/pccc_decoder_combined_XX_impl.cc.t
new file mode 100644
index 0000000000..21a5c0b3ae
--- /dev/null
+++ b/gr-trellis/lib/pccc_decoder_combined_XX_impl.cc.t
@@ -0,0 +1,139 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "@NAME@.h"
+#include <gr_io_signature.h>
+#include <iostream>
+#include <trellis/core_algorithms.h>
+
+namespace gr {
+ namespace trellis {
+
+ static const float INF = 1.0e9;
+
+ @BASE_NAME@::sptr
+ @BASE_NAME@::make(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE,
+ int D,
+ const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling)
+ {
+ return gnuradio::get_initial_sptr
+ (new @NAME@(FSMo, STo0, SToK, FSMi, STi0, STiK,
+ INTERLEAVER, blocklength, repetitions,
+ SISO_TYPE, D, TABLE,METRIC_TYPE, scaling));
+ }
+
+ @IMPL_NAME@::@IMPL_NAME@(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE,
+ int D,
+ const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling)
+ : gr_block("@BASE_NAME@",
+ gr_make_io_signature(1, 1, sizeof(@I_TYPE@)),
+ gr_make_io_signature(1, 1, sizeof(@O_TYPE@))),
+ d_FSMo(FSMo), d_STo0(STo0), d_SToK(SToK),
+ d_FSMi(FSMi), d_STi0(STi0), d_STiK(STiK),
+ d_INTERLEAVER(INTERLEAVER),
+ d_blocklength(blocklength),
+ d_repetitions(repetitions),
+ d_SISO_TYPE(SISO_TYPE),
+ d_D(D),
+ d_TABLE(TABLE),
+ d_METRIC_TYPE(METRIC_TYPE),
+ d_scaling(scaling)
+ {
+ assert(d_FSMo.I() == d_FSMi.I());
+ set_relative_rate (1.0 / ((double) d_D));
+ set_output_multiple (d_blocklength);
+ }
+
+ @IMPL_NAME@::~@IMPL_NAME@()
+ {
+ }
+
+ void
+ @IMPL_NAME@::set_scaling(float scaling)
+ {
+ d_scaling = scaling;
+ }
+
+ void
+ @IMPL_NAME@::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ int input_required = d_D * noutput_items;
+ ninput_items_required[0] = input_required;
+ }
+
+ //===========================================================
+
+ int
+ @IMPL_NAME@::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int nblocks = noutput_items / d_blocklength;
+
+ float (*p2min)(float, float) = NULL;
+ if(d_SISO_TYPE == TRELLIS_MIN_SUM)
+ p2min = &min;
+ else if(d_SISO_TYPE == TRELLIS_SUM_PRODUCT)
+ p2min = &min_star;
+
+ const @I_TYPE@ *in = (const @I_TYPE@ *) input_items[0];
+ @O_TYPE@ *out = (@O_TYPE@ *) output_items[0];
+ for (int n=0;n<nblocks;n++) {
+ pccc_decoder_combined(d_FSMo, d_STo0, d_SToK,
+ d_FSMi, d_STi0, d_STiK,
+ d_INTERLEAVER, d_blocklength, d_repetitions,
+ p2min,
+ d_D,d_TABLE,
+ d_METRIC_TYPE,
+ d_scaling,
+ &(in[n*d_blocklength*d_D]),
+ &(out[n*d_blocklength]));
+ }
+
+ consume_each(d_D * noutput_items);
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/pccc_decoder_combined_XX_impl.h.t b/gr-trellis/lib/pccc_decoder_combined_XX_impl.h.t
new file mode 100644
index 0000000000..4c3655f40d
--- /dev/null
+++ b/gr-trellis/lib/pccc_decoder_combined_XX_impl.h.t
@@ -0,0 +1,93 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifndef @GUARD_NAME@
+#define @GUARD_NAME@
+
+#include <trellis/@BASE_NAME@.h>
+
+namespace gr {
+ namespace trellis {
+
+ class @IMPL_NAME@ : public @BASE_NAME@
+ {
+ private:
+ fsm d_FSMo;
+ int d_STo0;
+ int d_SToK;
+ fsm d_FSMi;
+ int d_STi0;
+ int d_STiK;
+ interleaver d_INTERLEAVER;
+ int d_blocklength;
+ int d_repetitions;
+ siso_type_t d_SISO_TYPE;
+ int d_D;
+ std::vector<@I_TYPE@> d_TABLE;
+ digital::trellis_metric_type_t d_METRIC_TYPE;
+ float d_scaling;
+ std::vector<float> d_buffer;
+
+ public:
+ @IMPL_NAME@(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE,
+ int D,
+ const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling);
+ ~@IMPL_NAME@();
+
+ fsm FSM1() const { return d_FSMo; }
+ fsm FSM2() const { return d_FSMi; }
+ int ST10() const { return d_STo0; }
+ int ST1K() const { return d_SToK; }
+ int ST20() const { return d_STi0; }
+ int ST2K() const { return d_STiK; }
+ interleaver INTERLEAVER() const { return d_INTERLEAVER; }
+ int blocklength() const { return d_blocklength; }
+ int repetitions() const { return d_repetitions; }
+ int D() const { return d_D; }
+ std::vector<@I_TYPE@> TABLE() const { return d_TABLE; }
+ digital::trellis_metric_type_t METRIC_TYPE() const { return d_METRIC_TYPE; }
+ siso_type_t SISO_TYPE() const { return d_SISO_TYPE; }
+ float scaling() const { return d_scaling; }
+ void set_scaling(float scaling);
+
+ 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);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* @GUARD_NAME@ */
diff --git a/gr-trellis/lib/pccc_encoder_XX_impl.cc.t b/gr-trellis/lib/pccc_encoder_XX_impl.cc.t
new file mode 100644
index 0000000000..4e804729a2
--- /dev/null
+++ b/gr-trellis/lib/pccc_encoder_XX_impl.cc.t
@@ -0,0 +1,91 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "@NAME@.h"
+#include <gr_io_signature.h>
+#include <iostream>
+
+namespace gr {
+ namespace trellis {
+
+ @BASE_NAME@::sptr
+ @BASE_NAME@::make(const fsm &FSM1, int ST1,
+ const fsm &FSM2, int ST2,
+ const interleaver &INTERLEAVER,
+ int blocklength)
+ {
+ return gnuradio::get_initial_sptr
+ (new @IMPL_NAME@(FSM1, ST1, FSM2, ST2, INTERLEAVER, blocklength));
+ }
+
+ @IMPL_NAME@::@IMPL_NAME@(const fsm &FSM1, int ST1,
+ const fsm &FSM2, int ST2,
+ const interleaver &INTERLEAVER,
+ int blocklength)
+ : gr_sync_block("@BASE_NAME@",
+ gr_make_io_signature(1, 1, sizeof(@I_TYPE@)),
+ gr_make_io_signature(1, 1, sizeof(@O_TYPE@))),
+ d_FSM1(FSM1), d_ST1(ST1),
+ d_FSM2(FSM2), d_ST2(ST2),
+ d_INTERLEAVER(INTERLEAVER),
+ d_blocklength(blocklength)
+ {
+ assert(d_FSM1.I() == d_FSM2.I());
+ set_output_multiple(d_blocklength);
+ d_buffer.resize(d_blocklength);
+ }
+
+ @IMPL_NAME@::~@IMPL_NAME@()
+ {
+ }
+
+ int
+ @NAME@::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ for(int b = 0 ; b<noutput_items/d_blocklength; b++) {
+ const @I_TYPE@ *in = (const @I_TYPE@*)input_items[0]+b*d_blocklength;
+ @O_TYPE@ *out = (@O_TYPE@*)output_items[0]+b*d_blocklength;
+
+ int ST1_tmp = d_ST1;
+ int ST2_tmp = d_ST2;
+ for(int i = 0; i < d_blocklength; i++) {
+ int k = d_INTERLEAVER.INTER()[i];
+ int o1 = d_FSM1.OS()[ST1_tmp*d_FSM1.I()+in[i]];
+ ST1_tmp = (int) d_FSM1.NS()[ST1_tmp*d_FSM1.I()+in[i]];
+ int o2 = d_FSM2.OS()[ST2_tmp*d_FSM2.I()+in[k]];
+ ST2_tmp = (int) d_FSM2.NS()[ST2_tmp*d_FSM2.I()+in[k]];
+ out[i] = (@O_TYPE@) (o1*d_FSM1.O() + o2);
+ }
+ }
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/pccc_encoder_XX_impl.h.t b/gr-trellis/lib/pccc_encoder_XX_impl.h.t
new file mode 100644
index 0000000000..1eed3702be
--- /dev/null
+++ b/gr-trellis/lib/pccc_encoder_XX_impl.h.t
@@ -0,0 +1,66 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifndef @GUARD_NAME@
+#define @GUARD_NAME@
+
+#include <trellis/@BASE_NAME@.h>
+
+namespace gr {
+ namespace trellis {
+
+ class @IMPL_NAME@ : public @BASE_NAME@
+ {
+ private:
+ fsm d_FSM1;
+ int d_ST1;
+ fsm d_FSM2;
+ int d_ST2;
+ interleaver d_INTERLEAVER;
+ int d_blocklength;
+ std::vector<int> d_buffer;
+
+ public:
+ @IMPL_NAME@(const fsm &FSM1, int ST1,
+ const fsm &FSM2, int ST2,
+ const interleaver &INTERLEAVER,
+ int blocklength);
+ ~@IMPL_NAME@();
+
+ fsm FSM1() const { return d_FSM1; }
+ int ST1() const { return d_ST1; }
+ fsm FSM2() const { return d_FSM2; }
+ int ST2() const { return d_ST2; }
+ interleaver INTERLEAVER() const { return d_INTERLEAVER; }
+ int blocklength() const { return d_blocklength; }
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* @GUARD_NAME@ */
diff --git a/gr-trellis/lib/permutation_impl.cc b/gr-trellis/lib/permutation_impl.cc
new file mode 100644
index 0000000000..da82e46832
--- /dev/null
+++ b/gr-trellis/lib/permutation_impl.cc
@@ -0,0 +1,90 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "permutation_impl.h"
+#include <gr_io_signature.h>
+#include <iostream>
+#include <string.h>
+
+namespace gr {
+ namespace trellis {
+
+ permutation::sptr
+ permutation::make(int K, const std::vector<int> &TABLE,
+ int SYMS_PER_BLOCK, size_t BYTES_PER_SYMBOL)
+ {
+ return gnuradio::get_initial_sptr
+ (new permutation_impl(K,TABLE,SYMS_PER_BLOCK,BYTES_PER_SYMBOL));
+ }
+
+ permutation_impl::permutation_impl(int K, const std::vector<int> &TABLE,
+ int SYMS_PER_BLOCK, size_t BYTES_PER_SYMBOL)
+ : gr_sync_block("permutation",
+ gr_make_io_signature(1, -1, BYTES_PER_SYMBOL),
+ gr_make_io_signature(1, -1, BYTES_PER_SYMBOL)),
+ d_K(K), d_TABLE(TABLE),
+ d_SYMS_PER_BLOCK(SYMS_PER_BLOCK),
+ d_BYTES_PER_SYMBOL(BYTES_PER_SYMBOL)
+ {
+ set_output_multiple(d_K*SYMS_PER_BLOCK);
+ //std::cout << d_K << "\n";
+ }
+
+ permutation_impl::~permutation_impl()
+ {
+ }
+
+ int
+ permutation_impl::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int nstreams = input_items.size();
+
+ for(int m=0;m<nstreams;m++) {
+ const char *in = (const char *) input_items[m];
+ char *out = (char *) output_items[m];
+
+ // per stream processing
+ for(int i = 0; i < noutput_items/d_SYMS_PER_BLOCK; i++) {
+ // Index i refers to blocks.
+ // Begining of packet (in blocks)
+ int i0 = d_K*(i/d_K);
+ // position of block within packet (in blocks)
+ int j0 = i%d_K;
+ // new position of block within packet (in blocks)
+ int k0 = d_TABLE[j0];
+ memcpy(&(out[i*d_SYMS_PER_BLOCK*d_BYTES_PER_SYMBOL]),
+ &(in[(i0+k0)*d_SYMS_PER_BLOCK*d_BYTES_PER_SYMBOL]),
+ d_BYTES_PER_SYMBOL*d_SYMS_PER_BLOCK);
+ }
+ // end per stream processing
+ }
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/permutation_impl.h b/gr-trellis/lib/permutation_impl.h
new file mode 100644
index 0000000000..6e3ca2b2d7
--- /dev/null
+++ b/gr-trellis/lib/permutation_impl.h
@@ -0,0 +1,58 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_TRELLIS_PERMUTATION_IMPL_H
+#define INCLUDED_TRELLIS_PERMUTATION_IMPL_H
+
+#include <trellis/api.h>
+#include <trellis/permutation.h>
+
+namespace gr {
+ namespace trellis {
+
+ class permutation_impl : public permutation
+ {
+ private:
+ int d_K;
+ std::vector<int> d_TABLE;
+ int d_SYMS_PER_BLOCK;
+ size_t d_BYTES_PER_SYMBOL;
+
+ public:
+ permutation_impl(int K, const std::vector<int> &TABLE,
+ int SYMS_PER_BLOCK, size_t NBYTES);
+ ~permutation_impl();
+
+ int K() const { return d_K; }
+ const std::vector<int> & TABLE() const { return d_TABLE; }
+ int SYMS_PER_BLOCK() const { return d_SYMS_PER_BLOCK; }
+ size_t BYTES_PER_SYMBOL() const { return d_BYTES_PER_SYMBOL; }
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* INCLUDED_TRELLIS_PERMUTATION_IMPL_H */
diff --git a/gr-trellis/lib/quicksort_index.cc b/gr-trellis/lib/quicksort_index.cc
new file mode 100644
index 0000000000..02cd8a9134
--- /dev/null
+++ b/gr-trellis/lib/quicksort_index.cc
@@ -0,0 +1,70 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <trellis/quicksort_index.h>
+
+namespace gr {
+ namespace trellis {
+
+ template <class T> void
+ SWAP(T & a, T & b)
+ {
+ T temp = a;
+ a = b;
+ b = temp;
+ }
+
+ template <class T> void
+ quicksort_index (std::vector<T> & p, std::vector<int> & index,
+ int left, int right)
+ {
+ if(left < right) {
+ int i = left;
+ int j = right + 1;
+ T pivot = p[left];
+ do {
+ do
+ i++;
+ while ((p[i] < pivot) && (i < right));
+ do
+ j--;
+ while ((p[j] > pivot) && (j > left));
+ if (i < j) {
+ SWAP <T> (p[i],p[j]);
+ SWAP <int> (index[i],index[j]);
+ }
+ } while (i < j);
+ SWAP <T> (p[left], p[j]);
+ SWAP <int> (index[left], index[j]);
+ quicksort_index <T> (p,index, left, j-1);
+ quicksort_index <T> (p,index, j+1, right);
+ }
+ }
+
+ // instantiate an <int> version of the quicksort_index
+ //template <int> void SWAP (int & a, int & b);
+ template void
+ quicksort_index<int>(std::vector<int> & p, std::vector<int> & index,
+ int left, int right);
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/sccc_decoder_X_impl.cc.t b/gr-trellis/lib/sccc_decoder_X_impl.cc.t
new file mode 100644
index 0000000000..6eef46518d
--- /dev/null
+++ b/gr-trellis/lib/sccc_decoder_X_impl.cc.t
@@ -0,0 +1,118 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "@NAME@.h"
+#include <gr_io_signature.h>
+#include <iostream>
+#include <trellis/core_algorithms.h>
+
+namespace gr {
+ namespace trellis {
+
+ static const float INF = 1.0e9;
+
+ @BASE_NAME@::sptr
+ @BASE_NAME@::make(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE)
+ {
+ return gnuradio::get_initial_sptr
+ (new @IMPL_NAME@(FSMo, STo0, SToK, FSMi, STi0, STiK,
+ INTERLEAVER, blocklength, repetitions,
+ SISO_TYPE));
+ }
+
+ @IMPL_NAME@::@IMPL_NAME@(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE)
+ : gr_block("@BASE_NAME@",
+ gr_make_io_signature(1, 1, sizeof(float)),
+ gr_make_io_signature(1, 1, sizeof(@O_TYPE@))),
+ d_FSMo(FSMo), d_STo0(STo0), d_SToK(SToK),
+ d_FSMi(FSMi), d_STi0(STi0), d_STiK(STiK),
+ d_INTERLEAVER(INTERLEAVER),
+ d_blocklength(blocklength),
+ d_repetitions(repetitions),
+ d_SISO_TYPE(SISO_TYPE)
+ {
+ set_relative_rate(1.0 / ((double) d_FSMi.O()));
+ set_output_multiple(d_blocklength);
+ }
+
+ @IMPL_NAME@::~@IMPL_NAME@()
+ {
+ }
+
+ void
+ @IMPL_NAME@::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ int input_required = d_FSMi.O() * noutput_items ;
+ ninput_items_required[0] = input_required;
+ }
+
+ //===========================================================
+
+ int
+ @IMPL_NAME@::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int nblocks = noutput_items / d_blocklength;
+ float (*p2min)(float, float) = NULL;
+
+ if(d_SISO_TYPE == TRELLIS_MIN_SUM)
+ p2min = &min;
+ else if(d_SISO_TYPE == TRELLIS_SUM_PRODUCT)
+ p2min = &min_star;
+
+ const float *in = (const float*)input_items[0];
+ @O_TYPE@ *out = (@O_TYPE@*)output_items[0];
+
+ for(int n = 0; n < nblocks; n++) {
+ sccc_decoder(d_FSMo, d_STo0, d_SToK,
+ d_FSMi, d_STi0, d_STiK,
+ d_INTERLEAVER, d_blocklength, d_repetitions,
+ p2min,
+ &(in[n*d_blocklength*d_FSMi.O()]),
+ &(out[n*d_blocklength]));
+ }
+
+ consume_each(d_FSMi.O() * noutput_items );
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/sccc_decoder_X_impl.h.t b/gr-trellis/lib/sccc_decoder_X_impl.h.t
new file mode 100644
index 0000000000..31f4edc4b8
--- /dev/null
+++ b/gr-trellis/lib/sccc_decoder_X_impl.h.t
@@ -0,0 +1,80 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifndef @GUARD_NAME@
+#define @GUARD_NAME@
+
+#include <trellis/@BASE_NAME@.h>
+
+namespace gr {
+ namespace trellis {
+
+ class @IMPL_NAME@ : public @BASE_NAME@
+ {
+ private:
+ fsm d_FSMo;
+ int d_STo0;
+ int d_SToK;
+ fsm d_FSMi;
+ int d_STi0;
+ int d_STiK;
+ interleaver d_INTERLEAVER;
+ int d_blocklength;
+ int d_repetitions;
+ siso_type_t d_SISO_TYPE;
+ std::vector<float> d_buffer;
+
+ public:
+ @IMPL_NAME@(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE);
+ ~@IMPL_NAME@();
+
+ fsm FSMo() const { return d_FSMo; }
+ fsm FSMi() const { return d_FSMi; }
+ int STo0() const { return d_STo0; }
+ int SToK() const { return d_SToK; }
+ int STi0() const { return d_STi0; }
+ int STiK() const { return d_STiK; }
+ interleaver INTERLEAVER() const { return d_INTERLEAVER; }
+ int blocklength() const { return d_blocklength; }
+ int repetitions() const { return d_repetitions; }
+ siso_type_t SISO_TYPE() const { return d_SISO_TYPE; }
+
+ 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);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* @GUARD_NAME@ */
diff --git a/gr-trellis/lib/sccc_decoder_combined_XX_impl.cc.t b/gr-trellis/lib/sccc_decoder_combined_XX_impl.cc.t
new file mode 100644
index 0000000000..717f2c8e49
--- /dev/null
+++ b/gr-trellis/lib/sccc_decoder_combined_XX_impl.cc.t
@@ -0,0 +1,139 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "@NAME@.h"
+#include <gr_io_signature.h>
+#include <iostream>
+#include <trellis/core_algorithms.h>
+
+namespace gr {
+ namespace trellis {
+
+ static const float INF = 1.0e9;
+
+ @BASE_NAME@::sptr
+ @BASE_NAME@::make(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE,
+ int D,
+ const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling)
+ {
+ return gnuradio::get_initial_sptr
+ (new @IMPL_NAME@(FSMo, STo0, SToK, FSMi, STi0, STiK,
+ INTERLEAVER, blocklength, repetitions,
+ SISO_TYPE, D, TABLE,METRIC_TYPE, scaling));
+ }
+
+ @IMPL_NAME@::@IMPL_NAME@(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE,
+ int D,
+ const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling)
+ : gr_block("@BASE_NAME@",
+ gr_make_io_signature(1, 1, sizeof(@I_TYPE@)),
+ gr_make_io_signature(1, 1, sizeof(@O_TYPE@))),
+ d_FSMo(FSMo), d_STo0(STo0), d_SToK(SToK),
+ d_FSMi(FSMi), d_STi0(STi0), d_STiK(STiK),
+ d_INTERLEAVER(INTERLEAVER),
+ d_blocklength(blocklength),
+ d_repetitions(repetitions),
+ d_SISO_TYPE(SISO_TYPE),
+ d_D(D),
+ d_TABLE(TABLE),
+ d_METRIC_TYPE(METRIC_TYPE),
+ d_scaling(scaling)
+ {
+ set_relative_rate(1.0 / ((double) d_D));
+ set_output_multiple(d_blocklength);
+ }
+
+ @IMPL_NAME@::~@IMPL_NAME@()
+ {
+ }
+
+ void
+ @IMPL_NAME@::set_scaling(float scaling)
+ {
+ d_scaling = scaling;
+ }
+
+ void
+ @IMPL_NAME@::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ int input_required = d_D * noutput_items ;
+ ninput_items_required[0] = input_required;
+ }
+
+ //===========================================================
+
+ int
+ @IMPL_NAME@::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int nblocks = noutput_items / d_blocklength;
+ float (*p2min)(float, float) = NULL;
+
+ if(d_SISO_TYPE == TRELLIS_MIN_SUM)
+ p2min = &min;
+ else if(d_SISO_TYPE == TRELLIS_SUM_PRODUCT)
+ p2min = &min_star;
+
+ const @I_TYPE@ *in = (const @I_TYPE@*)input_items[0];
+ @O_TYPE@ *out = (@O_TYPE@*)output_items[0];
+
+ for(int n = 0; n < nblocks; n++) {
+ sccc_decoder_combined(d_FSMo, d_STo0, d_SToK,
+ d_FSMi, d_STi0, d_STiK,
+ d_INTERLEAVER, d_blocklength, d_repetitions,
+ p2min,
+ d_D,d_TABLE,
+ d_METRIC_TYPE,
+ d_scaling,
+ &(in[n*d_blocklength*d_D]),
+ &(out[n*d_blocklength]));
+ }
+
+ consume_each(d_D * noutput_items);
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/sccc_decoder_combined_XX_impl.h.t b/gr-trellis/lib/sccc_decoder_combined_XX_impl.h.t
new file mode 100644
index 0000000000..f3dbd1b4bb
--- /dev/null
+++ b/gr-trellis/lib/sccc_decoder_combined_XX_impl.h.t
@@ -0,0 +1,93 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifndef @GUARD_NAME@
+#define @GUARD_NAME@
+
+#include <trellis/@BASE_NAME@.h>
+
+namespace gr {
+ namespace trellis {
+
+ class @IMPL_NAME@ : public @BASE_NAME@
+ {
+ private:
+ fsm d_FSMo;
+ int d_STo0;
+ int d_SToK;
+ fsm d_FSMi;
+ int d_STi0;
+ int d_STiK;
+ interleaver d_INTERLEAVER;
+ int d_blocklength;
+ int d_repetitions;
+ siso_type_t d_SISO_TYPE;
+ int d_D;
+ std::vector<@I_TYPE@> d_TABLE;
+ digital::trellis_metric_type_t d_METRIC_TYPE;
+ float d_scaling;
+ std::vector<float> d_buffer;
+
+ public:
+ @IMPL_NAME@(const fsm &FSMo, int STo0, int SToK,
+ const fsm &FSMi, int STi0, int STiK,
+ const interleaver &INTERLEAVER,
+ int blocklength,
+ int repetitions,
+ siso_type_t SISO_TYPE,
+ int D,
+ const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t METRIC_TYPE,
+ float scaling);
+ ~@IMPL_NAME@();
+
+ fsm FSMo() const { return d_FSMo; }
+ fsm FSMi() const { return d_FSMi; }
+ int STo0() const { return d_STo0; }
+ int SToK() const { return d_SToK; }
+ int STi0() const { return d_STi0; }
+ int STiK() const { return d_STiK; }
+ interleaver INTERLEAVER() const { return d_INTERLEAVER; }
+ int blocklength() const { return d_blocklength; }
+ int repetitions() const { return d_repetitions; }
+ int D() const { return d_D; }
+ std::vector<@I_TYPE@> TABLE() const { return d_TABLE; }
+ digital::trellis_metric_type_t METRIC_TYPE() const { return d_METRIC_TYPE; }
+ siso_type_t SISO_TYPE() const { return d_SISO_TYPE; }
+ float scaling() const { return d_scaling; }
+ void set_scaling(float scaling);
+
+ 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);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* @GUARD_NAME@ */
diff --git a/gr-trellis/lib/sccc_encoder_XX_impl.cc.t b/gr-trellis/lib/sccc_encoder_XX_impl.cc.t
new file mode 100644
index 0000000000..390e65c4f3
--- /dev/null
+++ b/gr-trellis/lib/sccc_encoder_XX_impl.cc.t
@@ -0,0 +1,93 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "@NAME@.h"
+#include <gr_io_signature.h>
+#include <iostream>
+
+namespace gr {
+ namespace trellis {
+
+ @BASE_NAME@::sptr
+ @BASE_NAME@::make(const fsm &FSMo, int STo,
+ const fsm &FSMi, int STi,
+ const interleaver &INTERLEAVER,
+ int blocklength)
+ {
+ return gnuradio::get_initial_sptr
+ (new @IMPL_NAME@(FSMo, STo, FSMi, STi, INTERLEAVER, blocklength));
+ }
+
+ @IMPL_NAME@::@IMPL_NAME@(const fsm &FSMo, int STo,
+ const fsm &FSMi, int STi,
+ const interleaver &INTERLEAVER,
+ int blocklength)
+ : gr_sync_block("@BASE_NAME@",
+ gr_make_io_signature(1, 1, sizeof(@I_TYPE@)),
+ gr_make_io_signature(1, 1, sizeof(@O_TYPE@))),
+ d_FSMo(FSMo), d_STo(STo),
+ d_FSMi(FSMi), d_STi(STi),
+ d_INTERLEAVER(INTERLEAVER),
+ d_blocklength(blocklength)
+ {
+ set_output_multiple(d_blocklength);
+ d_buffer.resize(d_blocklength);
+ }
+
+ @IMPL_NAME@::~@IMPL_NAME@()
+ {
+ }
+
+ int
+ @IMPL_NAME@::work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ for(int b = 0; b < noutput_items/d_blocklength; b++) {
+ const @I_TYPE@ *in = (const @I_TYPE@*)input_items[0]+b*d_blocklength;
+ @O_TYPE@ *out = (@O_TYPE@*)output_items[0]+b*d_blocklength;
+
+ int STo_tmp = d_STo;
+ for(int i = 0; i < d_blocklength; i++) {
+ d_buffer[i] = d_FSMo.OS()[STo_tmp*d_FSMo.I()+in[i]];
+ STo_tmp = (int) d_FSMo.NS()[STo_tmp*d_FSMo.I()+in[i]];
+ }
+
+ int STi_tmp = d_STi;
+ for(int i = 0; i < d_blocklength; i++) {
+ int k = d_INTERLEAVER.INTER()[i];
+ out[i] = (@O_TYPE@) d_FSMi.OS()[STi_tmp*d_FSMi.I()+d_buffer[k]];
+ STi_tmp = (int) d_FSMi.NS()[STi_tmp*d_FSMi.I()+d_buffer[k]];
+ }
+ }
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
+
diff --git a/gr-trellis/lib/sccc_encoder_XX_impl.h.t b/gr-trellis/lib/sccc_encoder_XX_impl.h.t
new file mode 100644
index 0000000000..a3e582b5a0
--- /dev/null
+++ b/gr-trellis/lib/sccc_encoder_XX_impl.h.t
@@ -0,0 +1,66 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifndef @GUARD_NAME@
+#define @GUARD_NAME@
+
+#include <trellis/@BASE_NAME@.h>
+
+namespace gr {
+ namespace trellis {
+
+ class @IMPL_NAME@ : public @BASE_NAME@
+ {
+ private:
+ fsm d_FSMo;
+ int d_STo;
+ fsm d_FSMi;
+ int d_STi;
+ interleaver d_INTERLEAVER;
+ int d_blocklength;
+ std::vector<int> d_buffer;
+
+ public:
+ @IMPL_NAME@(const fsm &FSMo, int STo,
+ const fsm &FSMi, int STi,
+ const interleaver &INTERLEAVER,
+ int blocklength);
+ ~@IMPL_NAME@();
+
+ fsm FSMo() const { return d_FSMo; }
+ int STo() const { return d_STo; }
+ fsm FSMi() const { return d_FSMi; }
+ int STi() const { return d_STi; }
+ interleaver INTERLEAVER() const { return d_INTERLEAVER; }
+ int blocklength() const { return d_blocklength; }
+
+ int work(int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* @GUARD_NAME@ */
diff --git a/gr-trellis/lib/siso_combined_f_impl.cc b/gr-trellis/lib/siso_combined_f_impl.cc
new file mode 100644
index 0000000000..7514d46747
--- /dev/null
+++ b/gr-trellis/lib/siso_combined_f_impl.cc
@@ -0,0 +1,180 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "siso_combined_f_impl.h"
+#include <gr_io_signature.h>
+#include <stdexcept>
+#include <assert.h>
+#include <iostream>
+
+namespace gr {
+ namespace trellis {
+
+ static const float INF = 1.0e9;
+
+ siso_combined_f::sptr
+ siso_combined_f::make(const fsm &FSM, int K,
+ int S0, int SK,
+ bool POSTI, bool POSTO,
+ siso_type_t SISO_TYPE,
+ int D, const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t TYPE)
+ {
+ return gnuradio::get_initial_sptr
+ (new siso_combined_f_impl(FSM, K, S0, SK, POSTI, POSTO,
+ SISO_TYPE, D, TABLE, TYPE));
+ }
+
+ siso_combined_f_impl::siso_combined_f_impl(const fsm &FSM, int K,
+ int S0, int SK,
+ bool POSTI, bool POSTO,
+ siso_type_t SISO_TYPE,
+ int D, const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t TYPE)
+ : gr_block("siso_combined_f",
+ gr_make_io_signature(1, -1, sizeof(float)),
+ gr_make_io_signature(1, -1, sizeof(float))),
+ d_FSM(FSM), d_K(K), d_S0(S0), d_SK(SK),
+ d_POSTI(POSTI), d_POSTO(POSTO),
+ d_SISO_TYPE(SISO_TYPE),
+ d_D(D), d_TABLE(TABLE), d_TYPE(TYPE)//,
+ //d_alpha(FSM.S()*(K+1)),
+ //d_beta(FSM.S()*(K+1))
+ {
+ int multiple;
+ if(d_POSTI && d_POSTO)
+ multiple = d_FSM.I()+d_FSM.O();
+ else if(d_POSTI)
+ multiple = d_FSM.I();
+ else if(d_POSTO)
+ multiple = d_FSM.O();
+ else
+ throw std::runtime_error ("Not both POSTI and POSTO can be false.");
+
+ //printf("constructor: Multiple = %d\n",multiple);
+ set_output_multiple(d_K*multiple);
+
+ //what is the meaning of relative rate for a block with 2 inputs?
+ //set_relative_rate ( multiple / ((double) d_FSM.I()) );
+ // it turns out that the above gives problems in the scheduler, so
+ // let's try (assumption O>I)
+ //set_relative_rate ( multiple / ((double) d_FSM.O()) );
+ // I am tempted to automate like this
+ if(d_FSM.I() <= d_D)
+ set_relative_rate(multiple / ((double)d_D));
+ else
+ set_relative_rate(multiple / ((double)d_FSM.I()));
+ }
+
+ siso_combined_f_impl::~siso_combined_f_impl()
+ {
+ }
+
+ void
+ siso_combined_f_impl::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ int multiple;
+ if(d_POSTI && d_POSTO)
+ multiple = d_FSM.I()+d_FSM.O();
+ else if(d_POSTI)
+ multiple = d_FSM.I();
+ else if(d_POSTO)
+ multiple = d_FSM.O();
+ else
+ throw std::runtime_error ("Not both POSTI and POSTO can be false.");
+
+ //printf("forecast: Multiple = %d\n",multiple);
+ int input_required1 = d_FSM.I() * (noutput_items/multiple) ;
+ int input_required2 = d_D * (noutput_items/multiple) ;
+ //printf("forecast: Output requirements: %d\n",noutput_items);
+ //printf("forecast: Input requirements: %d %d\n",input_required1,input_required2);
+ unsigned ninputs = ninput_items_required.size();
+
+ for(unsigned int i = 0; i < ninputs/2; i++) {
+ ninput_items_required[2*i] = input_required1;
+ ninput_items_required[2*i+1] = input_required2;
+ }
+ }
+
+ int
+ siso_combined_f_impl::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int nstreams = output_items.size();
+ //printf("general_work:Streams: %d\n",nstreams);
+
+ int multiple;
+ if(d_POSTI && d_POSTO)
+ multiple = d_FSM.I()+d_FSM.O();
+ else if(d_POSTI)
+ multiple = d_FSM.I();
+ else if(d_POSTO)
+ multiple = d_FSM.O();
+ else
+ throw std::runtime_error("siso_combined_f_impl:: Not both POSTI and POSTO can be false.");
+
+ int nblocks = noutput_items / (d_K*multiple);
+ //printf("general_work:Blocks: %d\n",nblocks);
+ //for(int i=0;i<ninput_items.size();i++)
+ //printf("general_work:Input items available: %d\n",ninput_items[i]);
+
+ float (*p2min)(float, float) = NULL;
+ if(d_SISO_TYPE == TRELLIS_MIN_SUM)
+ p2min = &min;
+ else if(d_SISO_TYPE == TRELLIS_SUM_PRODUCT)
+ p2min = &min_star;
+
+ for(int m=0;m<nstreams;m++) {
+ const float *in1 = (const float*)input_items[2*m];
+ const float *in2 = (const float*)input_items[2*m+1];
+ float *out = (float *) output_items[m];
+ for(int n=0;n<nblocks;n++) {
+ siso_algorithm_combined(d_FSM.I(),d_FSM.S(),d_FSM.O(),
+ d_FSM.NS(),d_FSM.OS(),d_FSM.PS(),d_FSM.PI(),
+ d_K,d_S0,d_SK,
+ d_POSTI,d_POSTO,
+ p2min,
+ d_D,d_TABLE,d_TYPE,
+ &(in1[n*d_K*d_FSM.I()]),&(in2[n*d_K*d_D]),
+ &(out[n*d_K*multiple])//,
+ //d_alpha,d_beta
+ );
+ }
+ }
+
+ for(unsigned int i = 0; i < input_items.size()/2; i++) {
+ consume(2*i,d_FSM.I() * noutput_items / multiple );
+ consume(2*i+1,d_D * noutput_items / multiple );
+ }
+
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/siso_combined_f_impl.h b/gr-trellis/lib/siso_combined_f_impl.h
new file mode 100644
index 0000000000..27cef5e334
--- /dev/null
+++ b/gr-trellis/lib/siso_combined_f_impl.h
@@ -0,0 +1,79 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_TRELLIS_SISO_COMBINED_F_IMPL_H
+#define INCLUDED_TRELLIS_SISO_COMBINED_F_IMPL_H
+
+#include <trellis/siso_combined_f.h>
+
+namespace gr {
+ namespace trellis {
+
+ class siso_combined_f_impl : public siso_combined_f
+ {
+ private:
+ fsm d_FSM;
+ int d_K;
+ int d_S0;
+ int d_SK;
+ bool d_POSTI;
+ bool d_POSTO;
+ siso_type_t d_SISO_TYPE;
+ int d_D;
+ std::vector<float> d_TABLE;
+ digital::trellis_metric_type_t d_TYPE;
+ //std::vector<float> d_alpha;
+ //std::vector<float> d_beta;
+
+ public:
+ siso_combined_f_impl(const fsm &FSM, int K,
+ int S0, int SK,
+ bool POSTI, bool POSTO,
+ siso_type_t d_SISO_TYPE,
+ int D, const std::vector<float> &TABLE,
+ digital::trellis_metric_type_t TYPE);
+ ~siso_combined_f_impl();
+
+ fsm FSM() const { return d_FSM; }
+ int K() const { return d_K; }
+ int S0() const { return d_S0; }
+ int SK() const { return d_SK; }
+ bool POSTI() const { return d_POSTI; }
+ bool POSTO() const { return d_POSTO; }
+ siso_type_t SISO_TYPE() const { return d_SISO_TYPE; }
+ int D() const { return d_D; }
+ std::vector<float> TABLE() const { return d_TABLE; }
+ digital::trellis_metric_type_t TYPE() const { return d_TYPE; }
+
+ 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);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* INCLUDED_TRELLIS_SISO_COMBINED_F_IMPL_H */
diff --git a/gr-trellis/lib/siso_f_impl.cc b/gr-trellis/lib/siso_f_impl.cc
new file mode 100644
index 0000000000..b0484f6f37
--- /dev/null
+++ b/gr-trellis/lib/siso_f_impl.cc
@@ -0,0 +1,171 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "siso_f_impl.h"
+#include <gr_io_signature.h>
+#include <stdexcept>
+#include <assert.h>
+#include <iostream>
+
+namespace gr {
+ namespace trellis {
+
+ static const float INF = 1.0e9;
+
+ siso_f::sptr
+ siso_f::make(const fsm &FSM, int K,
+ int S0, int SK,
+ bool POSTI, bool POSTO,
+ siso_type_t SISO_TYPE)
+ {
+ return gnuradio::get_initial_sptr
+ (new siso_f_impl(FSM, K, S0, SK, POSTI, POSTO, SISO_TYPE));
+ }
+
+ siso_f_impl::siso_f_impl(const fsm &FSM, int K,
+ int S0, int SK,
+ bool POSTI, bool POSTO,
+ siso_type_t SISO_TYPE)
+ : gr_block("siso_f",
+ gr_make_io_signature(1, -1, sizeof(float)),
+ gr_make_io_signature(1, -1, sizeof(float))),
+ d_FSM(FSM), d_K(K),
+ d_S0(S0),d_SK(SK),
+ d_POSTI(POSTI), d_POSTO(POSTO),
+ d_SISO_TYPE(SISO_TYPE)//,
+ //d_alpha(FSM.S()*(K+1)),
+ //d_beta(FSM.S()*(K+1))
+ {
+ int multiple;
+ if(d_POSTI && d_POSTO)
+ multiple = d_FSM.I()+d_FSM.O();
+ else if(d_POSTI)
+ multiple = d_FSM.I();
+ else if(d_POSTO)
+ multiple = d_FSM.O();
+ else
+ throw std::runtime_error ("Not both POSTI and POSTO can be false.");
+
+ //printf("constructor: Multiple = %d\n",multiple);
+ set_output_multiple (d_K*multiple);
+
+ //what is the meaning of relative rate for a block with 2 inputs?
+ //set_relative_rate ( multiple / ((double) d_FSM.I()) );
+ // it turns out that the above gives problems in the scheduler, so
+ // let's try (assumption O>I)
+ //set_relative_rate ( multiple / ((double) d_FSM.O()) );
+ // I am tempted to automate like this
+ if(d_FSM.I() <= d_FSM.O())
+ set_relative_rate(multiple / ((double) d_FSM.O()));
+ else
+ set_relative_rate(multiple / ((double) d_FSM.I()));
+ }
+
+ siso_f_impl::~siso_f_impl()
+ {
+ }
+
+ void
+ siso_f_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required)
+ {
+ int multiple;
+ if(d_POSTI && d_POSTO)
+ multiple = d_FSM.I()+d_FSM.O();
+ else if(d_POSTI)
+ multiple = d_FSM.I();
+ else if(d_POSTO)
+ multiple = d_FSM.O();
+ else
+ throw std::runtime_error ("Not both POSTI and POSTO can be false.");
+
+ //printf("forecast: Multiple = %d\n",multiple);
+ int input_required1 = d_FSM.I() * (noutput_items/multiple) ;
+ int input_required2 = d_FSM.O() * (noutput_items/multiple) ;
+ //printf("forecast: Output requirements: %d\n",noutput_items);
+ //printf("forecast: Input requirements: %d %d\n",input_required1,input_required2);
+ unsigned ninputs = ninput_items_required.size();
+ for(unsigned int i = 0; i < ninputs/2; i++) {
+ ninput_items_required[2*i] = input_required1;
+ ninput_items_required[2*i+1] = input_required2;
+ }
+ }
+
+ int
+ siso_f_impl::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int nstreams = output_items.size();
+ //printf("general_work:Streams: %d\n",nstreams);
+ int multiple;
+ if(d_POSTI && d_POSTO)
+ multiple = d_FSM.I()+d_FSM.O();
+ else if(d_POSTI)
+ multiple = d_FSM.I();
+ else if(d_POSTO)
+ multiple = d_FSM.O();
+ else
+ throw std::runtime_error("siso_f_impl: Not both POSTI and POSTO can be false.\n");
+
+ int nblocks = noutput_items / (d_K*multiple);
+ //printf("general_work:Blocks: %d\n",nblocks);
+ //for(int i=0;i<ninput_items.size();i++)
+ //printf("general_work:Input items available: %d\n",ninput_items[i]);
+
+ float (*p2min)(float, float) = NULL;
+ if(d_SISO_TYPE == TRELLIS_MIN_SUM)
+ p2min = &min;
+ else if(d_SISO_TYPE == TRELLIS_SUM_PRODUCT)
+ p2min = &min_star;
+
+ for(int m = 0; m < nstreams; m++) {
+ const float *in1 = (const float*)input_items[2*m];
+ const float *in2 = (const float*)input_items[2*m+1];
+ float *out = (float*)output_items[m];
+ for(int n = 0;n < nblocks; n++) {
+ siso_algorithm(d_FSM.I(),d_FSM.S(),d_FSM.O(),
+ d_FSM.NS(),d_FSM.OS(),d_FSM.PS(),d_FSM.PI(),
+ d_K,d_S0,d_SK,
+ d_POSTI,d_POSTO,
+ p2min,
+ &(in1[n*d_K*d_FSM.I()]),&(in2[n*d_K*d_FSM.O()]),
+ &(out[n*d_K*multiple])//,
+ //d_alpha,d_beta
+ );
+ }
+ }
+
+ for(unsigned int i = 0; i < input_items.size()/2; i++) {
+ consume(2*i,d_FSM.I() * noutput_items / multiple );
+ consume(2*i+1,d_FSM.O() * noutput_items / multiple );
+ }
+
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/siso_f_impl.h b/gr-trellis/lib/siso_f_impl.h
new file mode 100644
index 0000000000..40766b97fa
--- /dev/null
+++ b/gr-trellis/lib/siso_f_impl.h
@@ -0,0 +1,75 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_TRELLIS_SISO_F_IMPL_H
+#define INCLUDED_TRELLIS_SISO_F_IMPL_H
+
+#include <trellis/api.h>
+#include <trellis/fsm.h>
+#include <trellis/siso_type.h>
+#include <trellis/core_algorithms.h>
+#include <trellis/siso_f.h>
+
+namespace gr {
+ namespace trellis {
+
+ class siso_f_impl : public siso_f
+ {
+ private:
+ fsm d_FSM;
+ int d_K;
+ int d_S0;
+ int d_SK;
+ bool d_POSTI;
+ bool d_POSTO;
+ siso_type_t d_SISO_TYPE;
+ //std::vector<float> d_alpha;
+ //std::vector<float> d_beta;
+
+ public:
+ siso_f_impl(const fsm &FSM, int K,
+ int S0, int SK,
+ bool POSTI, bool POSTO,
+ siso_type_t d_SISO_TYPE);
+ ~siso_f_impl();
+
+ fsm FSM() const { return d_FSM; }
+ int K() const { return d_K; }
+ int S0() const { return d_S0; }
+ int SK() const { return d_SK; }
+ bool POSTI() const { return d_POSTI; }
+ bool POSTO() const { return d_POSTO; }
+ siso_type_t SISO_TYPE() const { return d_SISO_TYPE; }
+
+ 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);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* INCLUDED_TRELLIS_SISO_F_IMPL_H */
diff --git a/gr-trellis/lib/viterbi_X_impl.cc.t b/gr-trellis/lib/viterbi_X_impl.cc.t
new file mode 100644
index 0000000000..5097cc2053
--- /dev/null
+++ b/gr-trellis/lib/viterbi_X_impl.cc.t
@@ -0,0 +1,99 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "@NAME@.h"
+#include <gr_io_signature.h>
+#include <iostream>
+
+namespace gr {
+ namespace trellis {
+
+ static const float INF = 1.0e9;
+
+ @BASE_NAME@::sptr
+ @BASE_NAME@::make(const fsm &FSM, int K,
+ int S0, int SK)
+ {
+ return gnuradio::get_initial_sptr
+ (new @IMPL_NAME@(FSM, K, S0, SK));
+ }
+
+ @IMPL_NAME@::@IMPL_NAME@(const fsm &FSM, int K,
+ int S0, int SK)
+ : gr_block("@BASE_NAME@",
+ gr_make_io_signature(1, -1, sizeof(float)),
+ gr_make_io_signature(1, -1, sizeof(@TYPE@))),
+ d_FSM(FSM), d_K(K), d_S0(S0), d_SK(SK)//,
+ //d_trace(FSM.S()*K)
+ {
+ set_relative_rate(1.0 / ((double)d_FSM.O()));
+ set_output_multiple(d_K);
+ }
+
+ @IMPL_NAME@::~@IMPL_NAME@()
+ {
+ }
+
+ void
+ @IMPL_NAME@::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ int input_required = d_FSM.O() * noutput_items;
+ unsigned ninputs = ninput_items_required.size();
+ for(unsigned int i = 0; i < ninputs; i++) {
+ ninput_items_required[i] = input_required;
+ }
+ }
+
+ int
+ @IMPL_NAME@::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int nstreams = input_items.size();
+ int nblocks = noutput_items / d_K;
+
+ for(int m = 0; m < nstreams; m++) {
+ const float *in = (const float*)input_items[m];
+ @TYPE@ *out = (@TYPE@*)output_items[m];
+
+ for(int n = 0; n < nblocks; n++) {
+ viterbi_algorithm(d_FSM.I(), d_FSM.S(), d_FSM.O(),
+ d_FSM.NS(), d_FSM.OS(), d_FSM.PS(),
+ d_FSM.PI(), d_K,d_S0, d_SK,
+ &(in[n*d_K*d_FSM.O()]), &(out[n*d_K]));
+ }
+ }
+
+ consume_each(d_FSM.O() * noutput_items);
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
diff --git a/gr-trellis/lib/viterbi_X_impl.h.t b/gr-trellis/lib/viterbi_X_impl.h.t
new file mode 100644
index 0000000000..accaacc158
--- /dev/null
+++ b/gr-trellis/lib/viterbi_X_impl.h.t
@@ -0,0 +1,65 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifndef @GUARD_NAME@
+#define @GUARD_NAME@
+
+#include <trellis/@BASE_NAME@.h>
+
+namespace gr {
+ namespace trellis {
+
+ class @IMPL_NAME@ : public @BASE_NAME@
+ {
+ private:
+ fsm d_FSM;
+ int d_K;
+ int d_S0;
+ int d_SK;
+ //std::vector<int> d_trace;
+
+ public:
+ @IMPL_NAME@(const fsm &FSM, int K,
+ int S0, int SK);
+ ~@IMPL_NAME@();
+
+ fsm FSM() const { return d_FSM; }
+ int K() const { return d_K; }
+ int S0() const { return d_S0; }
+ int SK() const { return d_SK; }
+
+ //std::vector<int> trace () const { return d_trace; }
+
+ 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);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* @GUARD_NAME@ */
diff --git a/gr-trellis/lib/viterbi_combined_XX_impl.cc.t b/gr-trellis/lib/viterbi_combined_XX_impl.cc.t
new file mode 100644
index 0000000000..95175bef95
--- /dev/null
+++ b/gr-trellis/lib/viterbi_combined_XX_impl.cc.t
@@ -0,0 +1,112 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2010,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "@NAME@.h"
+#include <gr_io_signature.h>
+#include <iostream>
+
+namespace gr {
+ namespace trellis {
+
+ static const float INF = 1.0e9;
+
+ @BASE_NAME@::sptr
+ @BASE_NAME@::make(const fsm &FSM, int K,
+ int S0, int SK, int D,
+ const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t TYPE)
+ {
+ return gnuradio::get_initial_sptr
+ (new @NAME@(FSM, K, S0, SK, D, TABLE,TYPE));
+ }
+
+ @IMPL_NAME@::@IMPL_NAME@(const fsm &FSM, int K,
+ int S0, int SK, int D,
+ const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t TYPE)
+ : gr_block("@BASE_NAME@",
+ gr_make_io_signature(1, -1, sizeof(@I_TYPE@)),
+ gr_make_io_signature(1, -1, sizeof(@O_TYPE@))),
+ d_FSM(FSM), d_K(K), d_S0(S0), d_SK(SK), d_D(D),
+ d_TABLE(TABLE), d_TYPE(TYPE)//,
+ //d_trace(FSM.S()*K)
+ {
+ set_relative_rate(1.0 / ((double)d_D));
+ set_output_multiple(d_K);
+ }
+
+ @IMPL_NAME@::~@IMPL_NAME@()
+ {
+ }
+
+ void
+ @IMPL_NAME@::set_TABLE(const std::vector<@I_TYPE@> &table)
+ {
+ d_TABLE = table;
+ }
+
+ void
+ @IMPL_NAME@::forecast(int noutput_items,
+ gr_vector_int &ninput_items_required)
+ {
+ int input_required = d_D * noutput_items;
+ unsigned ninputs = ninput_items_required.size();
+ for(unsigned int i = 0; i < ninputs; i++) {
+ ninput_items_required[i] = input_required;
+ }
+ }
+
+ int
+ @IMPL_NAME@::general_work(int noutput_items,
+ gr_vector_int &ninput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+ {
+ int nstreams = input_items.size();
+ int nblocks = noutput_items / d_K;
+
+ for(int m=0;m<nstreams;m++) {
+ const @I_TYPE@ *in = (const @I_TYPE@*)input_items[m];
+ @O_TYPE@ *out = (@O_TYPE@*)output_items[m];
+
+ for(int n=0;n<nblocks;n++) {
+ viterbi_algorithm_combined(d_FSM.I(), d_FSM.S(), d_FSM.O(),
+ d_FSM.NS(), d_FSM.OS(), d_FSM.PS(),
+ d_FSM.PI(), d_K,d_S0, d_SK, d_D,
+ d_TABLE, d_TYPE,
+ &(in[n*d_K*d_D]), &(out[n*d_K]));
+ }
+ }
+
+ consume_each(d_D * noutput_items);
+ return noutput_items;
+ }
+
+ } /* namespace trellis */
+} /* namespace gr */
+
diff --git a/gr-trellis/lib/viterbi_combined_XX_impl.h.t b/gr-trellis/lib/viterbi_combined_XX_impl.h.t
new file mode 100644
index 0000000000..df62001110
--- /dev/null
+++ b/gr-trellis/lib/viterbi_combined_XX_impl.h.t
@@ -0,0 +1,74 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004,2012 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 3, 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+// @WARNING@
+
+#ifndef @GUARD_NAME@
+#define @GUARD_NAME@
+
+#include <trellis/@BASE_NAME@.h>
+
+namespace gr {
+ namespace trellis {
+
+ class @IMPL_NAME@ : public @BASE_NAME@
+ {
+ private:
+ fsm d_FSM;
+ int d_K;
+ int d_S0;
+ int d_SK;
+ int d_D;
+ std::vector<@I_TYPE@> d_TABLE;
+ digital::trellis_metric_type_t d_TYPE;
+ //std::vector<int> d_trace;
+
+ public:
+ @IMPL_NAME@(const fsm &FSM, int K,
+ int S0, int SK, int D,
+ const std::vector<@I_TYPE@> &TABLE,
+ digital::trellis_metric_type_t TYPE);
+ ~@IMPL_NAME@();
+
+ fsm FSM() const { return d_FSM; }
+ int K() const { return d_K; }
+ int S0() const { return d_S0; }
+ int SK() const { return d_SK; }
+ int D() const { return d_D; }
+ std::vector<@I_TYPE@> TABLE() const { return d_TABLE; }
+ digital::trellis_metric_type_t TYPE() const { return d_TYPE; }
+ //std::vector<int> trace() const { return d_trace; }
+ void set_TABLE(const std::vector<@I_TYPE@> &table);
+
+ 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);
+ };
+
+ } /* namespace trellis */
+} /* namespace gr */
+
+#endif /* @GUARD_NAME@ */