├── CMakeLists.txt ├── MANIFEST.md ├── README.md ├── apps └── CMakeLists.txt ├── cmake ├── Modules │ ├── CMakeParseArgumentsCopy.cmake │ ├── lazyviterbiConfig.cmake │ └── targetConfig.cmake.in └── cmake_uninstall.cmake.in ├── docs ├── CMakeLists.txt ├── README.lazyviterbi └── doxygen │ ├── CMakeLists.txt │ ├── Doxyfile.in │ ├── Doxyfile.swig_doc.in │ ├── doxyxml │ ├── __init__.py │ ├── base.py │ ├── doxyindex.py │ ├── generated │ │ ├── __init__.py │ │ ├── compound.py │ │ ├── compoundsuper.py │ │ ├── index.py │ │ └── indexsuper.py │ └── text.py │ ├── other │ ├── group_defs.dox │ └── main_page.dox │ └── swig_doc.py ├── examples ├── README ├── ber_vs_ebn0_75_awgn.py ├── bitrate_vs_ebn0.py ├── figures │ ├── i5_775_171_133_bitrate.png │ ├── i5_775_229_159_bitrate.png │ ├── i5_775_5_7_bitrate.png │ └── i5_775_rsc_15_13_bitrate.png ├── fsm │ ├── 171_133.fsm │ ├── 229_159.fsm │ ├── 5_7.fsm │ └── rsc_15_13.fsm └── simple.grc ├── grc ├── CMakeLists.txt ├── lazyviterbi_dynamic_viterbi.block.yml ├── lazyviterbi_lazy_viterbi.block.yml ├── lazyviterbi_viterbi.block.yml ├── lazyviterbi_viterbi_volk_branch.block.yml └── lazyviterbi_viterbi_volk_state.block.yml ├── include └── lazyviterbi │ ├── CMakeLists.txt │ ├── api.h │ ├── dynamic_viterbi.h │ ├── lazy_viterbi.h │ ├── viterbi.h │ ├── viterbi_volk_branch.h │ └── viterbi_volk_state.h ├── lib ├── CMakeLists.txt ├── dynamic_viterbi_impl.cc ├── dynamic_viterbi_impl.h ├── lazy_viterbi_impl.cc ├── lazy_viterbi_impl.h ├── node.h ├── qa_lazyviterbi.cc ├── qa_lazyviterbi.h ├── test_lazyviterbi.cc ├── viterbi_impl.cc ├── viterbi_impl.h ├── viterbi_volk_branch_impl.cc ├── viterbi_volk_branch_impl.h ├── viterbi_volk_state_impl.cc └── viterbi_volk_state_impl.h ├── python ├── CMakeLists.txt ├── __init__.py ├── build_utils.py ├── build_utils_codes.py ├── qa_dynamic_viterbi.py ├── qa_lazy_viterbi.py ├── qa_viterbi.py ├── qa_viterbi_volk_branch.py └── qa_viterbi_volk_state.py └── swig ├── CMakeLists.txt └── lazyviterbi_swig.i /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011,2012,2014,2016,2018 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-lazyviterbi 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | 21 | ######################################################################## 22 | # Project setup 23 | ######################################################################## 24 | cmake_minimum_required(VERSION 3.8) 25 | project(gr-lazyviterbi CXX C) 26 | enable_testing() 27 | 28 | # Install to PyBOMBS target prefix if defined 29 | if(DEFINED ENV{PYBOMBS_PREFIX}) 30 | set(CMAKE_INSTALL_PREFIX $ENV{PYBOMBS_PREFIX}) 31 | message(STATUS "PyBOMBS installed GNU Radio. Setting CMAKE_INSTALL_PREFIX to $ENV{PYBOMBS_PREFIX}") 32 | endif() 33 | 34 | # Select the release build type by default to get optimization flags 35 | if(NOT CMAKE_BUILD_TYPE) 36 | set(CMAKE_BUILD_TYPE "Release") 37 | message(STATUS "Build type not specified: defaulting to release.") 38 | endif(NOT CMAKE_BUILD_TYPE) 39 | set(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE} CACHE STRING "") 40 | 41 | # Make sure our local CMake Modules path comes first 42 | list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_SOURCE_DIR}/cmake/Modules) 43 | 44 | # Set the version information here 45 | set(VERSION_MAJOR 1) 46 | set(VERSION_API 0) 47 | set(VERSION_ABI 0) 48 | set(VERSION_PATCH git) 49 | 50 | cmake_policy(SET CMP0011 NEW) 51 | 52 | # Enable generation of compile_commands.json for code completion engines 53 | set(CMAKE_EXPORT_COMPILE_COMMANDS ON) 54 | 55 | ######################################################################## 56 | # Compiler specific setup 57 | ######################################################################## 58 | if((CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR 59 | CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 60 | AND NOT WIN32) 61 | #http://gcc.gnu.org/wiki/Visibility 62 | add_definitions(-fvisibility=hidden) 63 | endif() 64 | 65 | IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 66 | SET(CMAKE_CXX_STANDARD 11) 67 | ELSEIF(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 68 | SET(CMAKE_CXX_STANDARD 11) 69 | ELSEIF(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 70 | SET(CMAKE_CXX_STANDARD 11) 71 | ELSE() 72 | message(WARNING "C++ standard could not be set because compiler is not GNU, Clang or MSVC.") 73 | ENDIF() 74 | 75 | IF(CMAKE_C_COMPILER_ID STREQUAL "GNU") 76 | SET(CMAKE_C_STANDARD 11) 77 | ELSEIF(CMAKE_C_COMPILER_ID MATCHES "Clang") 78 | SET(CMAKE_C_STANDARD 11) 79 | ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 80 | SET(CMAKE_C_STANDARD 11) 81 | ELSE() 82 | message(WARNING "C standard could not be set because compiler is not GNU, Clang or MSVC.") 83 | ENDIF() 84 | 85 | ######################################################################## 86 | # Install directories 87 | ######################################################################## 88 | find_package(Gnuradio "3.8" REQUIRED trellis digital filter blocks analog fft PATHS ${CMAKE_INSTALL_PREFIX} ) 89 | include(GrVersion) 90 | 91 | include(GrPlatform) #define LIB_SUFFIX 92 | 93 | if(NOT CMAKE_MODULES_DIR) 94 | set(CMAKE_MODULES_DIR lib${LIB_SUFFIX}/cmake) 95 | endif(NOT CMAKE_MODULES_DIR) 96 | 97 | set(GR_INCLUDE_DIR include/lazyviterbi) 98 | set(GR_CMAKE_DIR ${CMAKE_MODULES_DIR}/lazyviterbi) 99 | set(GR_PKG_DATA_DIR ${GR_DATA_DIR}/${CMAKE_PROJECT_NAME}) 100 | set(GR_PKG_DOC_DIR ${GR_DOC_DIR}/${CMAKE_PROJECT_NAME}) 101 | set(GR_PKG_CONF_DIR ${GR_CONF_DIR}/${CMAKE_PROJECT_NAME}/conf.d) 102 | set(GR_PKG_LIBEXEC_DIR ${GR_LIBEXEC_DIR}/${CMAKE_PROJECT_NAME}) 103 | 104 | ######################################################################## 105 | # On Apple only, set install name and use rpath correctly, if not already set 106 | ######################################################################## 107 | if(APPLE) 108 | if(NOT CMAKE_INSTALL_NAME_DIR) 109 | set(CMAKE_INSTALL_NAME_DIR 110 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE 111 | PATH "Library Install Name Destination Directory" FORCE) 112 | endif(NOT CMAKE_INSTALL_NAME_DIR) 113 | if(NOT CMAKE_INSTALL_RPATH) 114 | set(CMAKE_INSTALL_RPATH 115 | ${CMAKE_INSTALL_PREFIX}/${GR_LIBRARY_DIR} CACHE 116 | PATH "Library Install RPath" FORCE) 117 | endif(NOT CMAKE_INSTALL_RPATH) 118 | if(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) 119 | set(CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE 120 | BOOL "Do Build Using Library Install RPath" FORCE) 121 | endif(NOT CMAKE_BUILD_WITH_INSTALL_RPATH) 122 | endif(APPLE) 123 | 124 | ######################################################################## 125 | # Find gnuradio build dependencies 126 | ######################################################################## 127 | find_package(Doxygen) 128 | 129 | ######################################################################## 130 | # Setup doxygen option 131 | ######################################################################## 132 | if(DOXYGEN_FOUND) 133 | option(ENABLE_DOXYGEN "Build docs using Doxygen" ON) 134 | else(DOXYGEN_FOUND) 135 | option(ENABLE_DOXYGEN "Build docs using Doxygen" OFF) 136 | endif(DOXYGEN_FOUND) 137 | 138 | ######################################################################## 139 | # Create uninstall target 140 | ######################################################################## 141 | configure_file( 142 | ${CMAKE_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in 143 | ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 144 | @ONLY) 145 | 146 | add_custom_target(uninstall 147 | ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake 148 | ) 149 | 150 | 151 | ######################################################################## 152 | # Add subdirectories 153 | ######################################################################## 154 | add_subdirectory(include/lazyviterbi) 155 | add_subdirectory(lib) 156 | add_subdirectory(apps) 157 | add_subdirectory(docs) 158 | add_subdirectory(swig) 159 | add_subdirectory(python) 160 | add_subdirectory(grc) 161 | 162 | ######################################################################## 163 | # Install cmake search helper for this library 164 | ######################################################################## 165 | 166 | install(FILES cmake/Modules/lazyviterbiConfig.cmake 167 | DESTINATION ${CMAKE_MODULES_DIR}/lazyviterbi 168 | ) 169 | -------------------------------------------------------------------------------- /MANIFEST.md: -------------------------------------------------------------------------------- 1 | title: The LAZYVITERBI OOT Module 2 | brief: Short description of gr-lazyviterbi 3 | tags: # Tags are arbitrary, but look at CGRAN what other authors are using 4 | - sdr 5 | author: 6 | - Author Name 7 | copyright_owner: 8 | - Copyright Owner 1 9 | license: 10 | #repo: # Put the URL of the repository here, or leave blank for default 11 | #website: # If you have a separate project website, put it here 12 | #icon: # Put a URL to a square image here that will be used as an icon on CGRAN 13 | --- 14 | A longer, multi-line description of gr-lazyviterbi. 15 | You may use some *basic* Markdown here. 16 | If left empty, it will try to find a README file instead. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GNURadio implementation of the Lazy Viterbi algorithm. 2 | 3 | *Now with two Volk-accelerated implementations!* 4 | 5 | This module contains a three blocks, which are drop-in replacement for the Viterbi 6 | block of gr-trellis: 7 | * Lazy Viterbi: implements the Viterbi algorithm for decoding or equalization in the way described 8 | in Feldman, Jon & Abou-Faycal, Ibrahim & Frigo, Matteo. (2002). 9 | A Fast Maximum-Likelihood Decoder for Convolutional Codes. Vehicular Technology Conference, 1988, IEEE 38th. 10 | 10.1109/VETECF.2002.1040367. 11 | This implementation provides a significant speedup at moderate SNRs, but is slower 12 | at low SNR. 13 | * Viterbi: implements the classical Viterbi algorithm. 14 | This implementation is better-suited than Lazy Viterbi for low SNRs. 15 | * Dynamic Viterbi: Switch between the two implementations mentionned above, 16 | depending on SNR. 17 | * Viterbi Volk (branch parallelization): implements the classical Viterbi algorithm, but uses Volk to enable parallell processing of branches leading to each state (each state is treated sequentially). 18 | This implementation should be more suited to trellis having more transitions between branches than states (like turbo-Hadamrd / turbo-FSK types of trellis). 19 | * Viterbi Volk (state parallelization): implements the classical Viterbi algorithm, but uses Volk to enable parallell processing of states (Add-Compare-Select is done on multiple states at the same time). 20 | This implementation should be more suited to trellis having states than transitions between states (it is the case of most error correcting codes). 21 | 22 | # Installation 23 | 24 | ## Requirements 25 | 26 | `gr-lazyviterbi` depends on: 27 | * GNURadio >= 3.8.0 28 | * Volk >= 2.0.0 29 | * cmake (same version as for GNURadio 3.8) 30 | 31 | ## Under linux 32 | 33 | Within `gr-lazyviterbi` directory, and as a regular user: 34 | ```sh 35 | $ mkdir build 36 | $ cd build 37 | $ cmake .. 38 | $ make -j4 39 | ``` 40 | A root: 41 | ```sh 42 | # make install 43 | ``` 44 | 45 | # Examples 46 | 47 | One GRC example is provided in the examples/ directory: 48 | * `simple.grc` simple example showing how each decoder should be use in a typical flowgraph. You will have to populate the variable `base_dir`, and put the full path to the source folder of `gr-lazyviterbi` (for example: `/usr/local/src/gr-lazyviterbi`). 49 | 50 | There are also two python scripts : 51 | * `ber_vs_ebn0_75_awgn.py` lets you compare the BER of this algorithm 52 | and the gr-trellis's implementation of the classical Viterbi algorithm for a 53 | transmission AWGN channel with the (7,5) convolutional code (there 54 | should be a slight difference of performance du to metrics quantization from our 55 | implementation) ; 56 | * `bitrate_vs_ebn0.py` compare the speed of this algorithm and the gr-trellis's 57 | implementation of the classical Viterbi algorithm for a transmission AWGN 58 | channel with the (229,159) convolutional code. 59 | The convolutional code used in this script can easily be changed by supplying its 60 | treillis in a FSM file (see gr-trellis documentation), to see what kind of speedup 61 | can be expected for a particular use case. 62 | 63 | # Performance 64 | 65 | There is no best implementation. Performance depends on the trellis, the SNR of the transmission, the processor in your computer. 66 | Bellow is bitrate comparisons for some trellis, using a computer equiped with an Intel core i5 775 (see `examples/bitrate_vs_ebn0.py` for details on simulation parameters). 67 | 68 | (5,7) Convolutional code. 69 | 70 | ![(5,7) CC](examples/figures/i5_775_5_7_bitrate.png) 71 | 72 | (15,13) Recursive Systematic Convolutional (RSC) code. 73 | 74 | ![(15,13) RSC](examples/figures/i5_775_rsc_15_13_bitrate.png) 75 | 76 | (171,133) Convolutional code. 77 | 78 | ![(171,133) CC](examples/figures/i5_775_171_133_bitrate.png) 79 | 80 | (229,159) Convolutional code. 81 | 82 | ![(229,159) CC](examples/figures/i5_775_229_159_bitrate.png) 83 | -------------------------------------------------------------------------------- /apps/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-lazyviterbi 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | 21 | include(GrPython) 22 | 23 | GR_PYTHON_INSTALL( 24 | PROGRAMS 25 | DESTINATION bin 26 | ) 27 | -------------------------------------------------------------------------------- /cmake/Modules/CMakeParseArgumentsCopy.cmake: -------------------------------------------------------------------------------- 1 | # CMAKE_PARSE_ARGUMENTS( args...) 2 | # 3 | # CMAKE_PARSE_ARGUMENTS() is intended to be used in macros or functions for 4 | # parsing the arguments given to that macro or function. 5 | # It processes the arguments and defines a set of variables which hold the 6 | # values of the respective options. 7 | # 8 | # The argument contains all options for the respective macro, 9 | # i.e. keywords which can be used when calling the macro without any value 10 | # following, like e.g. the OPTIONAL keyword of the install() command. 11 | # 12 | # The argument contains all keywords for this macro 13 | # which are followed by one value, like e.g. DESTINATION keyword of the 14 | # install() command. 15 | # 16 | # The argument contains all keywords for this macro 17 | # which can be followed by more than one value, like e.g. the TARGETS or 18 | # FILES keywords of the install() command. 19 | # 20 | # When done, CMAKE_PARSE_ARGUMENTS() will have defined for each of the 21 | # keywords listed in , and 22 | # a variable composed of the given 23 | # followed by "_" and the name of the respective keyword. 24 | # These variables will then hold the respective value from the argument list. 25 | # For the keywords this will be TRUE or FALSE. 26 | # 27 | # All remaining arguments are collected in a variable 28 | # _UNPARSED_ARGUMENTS, this can be checked afterwards to see whether 29 | # your macro was called with unrecognized parameters. 30 | # 31 | # As an example here a my_install() macro, which takes similar arguments as the 32 | # real install() command: 33 | # 34 | # function(MY_INSTALL) 35 | # set(options OPTIONAL FAST) 36 | # set(oneValueArgs DESTINATION RENAME) 37 | # set(multiValueArgs TARGETS CONFIGURATIONS) 38 | # cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) 39 | # ... 40 | # 41 | # Assume my_install() has been called like this: 42 | # my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub) 43 | # 44 | # After the cmake_parse_arguments() call the macro will have set the following 45 | # variables: 46 | # MY_INSTALL_OPTIONAL = TRUE 47 | # MY_INSTALL_FAST = FALSE (this option was not used when calling my_install() 48 | # MY_INSTALL_DESTINATION = "bin" 49 | # MY_INSTALL_RENAME = "" (was not used) 50 | # MY_INSTALL_TARGETS = "foo;bar" 51 | # MY_INSTALL_CONFIGURATIONS = "" (was not used) 52 | # MY_INSTALL_UNPARSED_ARGUMENTS = "blub" (no value expected after "OPTIONAL" 53 | # 54 | # You can the continue and process these variables. 55 | # 56 | # Keywords terminate lists of values, e.g. if directly after a one_value_keyword 57 | # another recognized keyword follows, this is interpreted as the beginning of 58 | # the new option. 59 | # E.g. my_install(TARGETS foo DESTINATION OPTIONAL) would result in 60 | # MY_INSTALL_DESTINATION set to "OPTIONAL", but MY_INSTALL_DESTINATION would 61 | # be empty and MY_INSTALL_OPTIONAL would be set to TRUE therefore. 62 | 63 | #============================================================================= 64 | # Copyright 2010 Alexander Neundorf 65 | # 66 | # Distributed under the OSI-approved BSD License (the "License"); 67 | # see accompanying file Copyright.txt for details. 68 | # 69 | # This software is distributed WITHOUT ANY WARRANTY; without even the 70 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 71 | # See the License for more information. 72 | #============================================================================= 73 | # (To distribute this file outside of CMake, substitute the full 74 | # License text for the above reference.) 75 | 76 | 77 | if(__CMAKE_PARSE_ARGUMENTS_INCLUDED) 78 | return() 79 | endif() 80 | set(__CMAKE_PARSE_ARGUMENTS_INCLUDED TRUE) 81 | 82 | 83 | function(CMAKE_PARSE_ARGUMENTS prefix _optionNames _singleArgNames _multiArgNames) 84 | # first set all result variables to empty/FALSE 85 | foreach(arg_name ${_singleArgNames} ${_multiArgNames}) 86 | set(${prefix}_${arg_name}) 87 | endforeach(arg_name) 88 | 89 | foreach(option ${_optionNames}) 90 | set(${prefix}_${option} FALSE) 91 | endforeach(option) 92 | 93 | set(${prefix}_UNPARSED_ARGUMENTS) 94 | 95 | set(insideValues FALSE) 96 | set(currentArgName) 97 | 98 | # now iterate over all arguments and fill the result variables 99 | foreach(currentArg ${ARGN}) 100 | list(FIND _optionNames "${currentArg}" optionIndex) # ... then this marks the end of the arguments belonging to this keyword 101 | list(FIND _singleArgNames "${currentArg}" singleArgIndex) # ... then this marks the end of the arguments belonging to this keyword 102 | list(FIND _multiArgNames "${currentArg}" multiArgIndex) # ... then this marks the end of the arguments belonging to this keyword 103 | 104 | if(${optionIndex} EQUAL -1 AND ${singleArgIndex} EQUAL -1 AND ${multiArgIndex} EQUAL -1) 105 | if(insideValues) 106 | if("${insideValues}" STREQUAL "SINGLE") 107 | set(${prefix}_${currentArgName} ${currentArg}) 108 | set(insideValues FALSE) 109 | elseif("${insideValues}" STREQUAL "MULTI") 110 | list(APPEND ${prefix}_${currentArgName} ${currentArg}) 111 | endif() 112 | else(insideValues) 113 | list(APPEND ${prefix}_UNPARSED_ARGUMENTS ${currentArg}) 114 | endif(insideValues) 115 | else() 116 | if(NOT ${optionIndex} EQUAL -1) 117 | set(${prefix}_${currentArg} TRUE) 118 | set(insideValues FALSE) 119 | elseif(NOT ${singleArgIndex} EQUAL -1) 120 | set(currentArgName ${currentArg}) 121 | set(${prefix}_${currentArgName}) 122 | set(insideValues "SINGLE") 123 | elseif(NOT ${multiArgIndex} EQUAL -1) 124 | set(currentArgName ${currentArg}) 125 | set(${prefix}_${currentArgName}) 126 | set(insideValues "MULTI") 127 | endif() 128 | endif() 129 | 130 | endforeach(currentArg) 131 | 132 | # propagate the result variables to the caller: 133 | foreach(arg_name ${_singleArgNames} ${_multiArgNames} ${_optionNames}) 134 | set(${prefix}_${arg_name} ${${prefix}_${arg_name}} PARENT_SCOPE) 135 | endforeach(arg_name) 136 | set(${prefix}_UNPARSED_ARGUMENTS ${${prefix}_UNPARSED_ARGUMENTS} PARENT_SCOPE) 137 | 138 | endfunction(CMAKE_PARSE_ARGUMENTS _options _singleArgs _multiArgs) 139 | -------------------------------------------------------------------------------- /cmake/Modules/lazyviterbiConfig.cmake: -------------------------------------------------------------------------------- 1 | INCLUDE(FindPkgConfig) 2 | PKG_CHECK_MODULES(PC_LAZYVITERBI lazyviterbi) 3 | 4 | FIND_PATH( 5 | LAZYVITERBI_INCLUDE_DIRS 6 | NAMES lazyviterbi/api.h 7 | HINTS $ENV{LAZYVITERBI_DIR}/include 8 | ${PC_LAZYVITERBI_INCLUDEDIR} 9 | PATHS ${CMAKE_INSTALL_PREFIX}/include 10 | /usr/local/include 11 | /usr/include 12 | ) 13 | 14 | FIND_LIBRARY( 15 | LAZYVITERBI_LIBRARIES 16 | NAMES gnuradio-lazyviterbi 17 | HINTS $ENV{LAZYVITERBI_DIR}/lib 18 | ${PC_LAZYVITERBI_LIBDIR} 19 | PATHS ${CMAKE_INSTALL_PREFIX}/lib 20 | ${CMAKE_INSTALL_PREFIX}/lib64 21 | /usr/local/lib 22 | /usr/local/lib64 23 | /usr/lib 24 | /usr/lib64 25 | ) 26 | 27 | include("${CMAKE_CURRENT_LIST_DIR}/lazyviterbiTarget.cmake") 28 | 29 | INCLUDE(FindPackageHandleStandardArgs) 30 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(LAZYVITERBI DEFAULT_MSG LAZYVITERBI_LIBRARIES LAZYVITERBI_INCLUDE_DIRS) 31 | MARK_AS_ADVANCED(LAZYVITERBI_LIBRARIES LAZYVITERBI_INCLUDE_DIRS) 32 | -------------------------------------------------------------------------------- /cmake/Modules/targetConfig.cmake.in: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | include(CMakeFindDependencyMacro) 21 | 22 | set(target_deps "@TARGET_DEPENDENCIES@") 23 | foreach(dep IN LISTS target_deps) 24 | find_dependency(${dep}) 25 | endforeach() 26 | include("${CMAKE_CURRENT_LIST_DIR}/@TARGET@Targets.cmake") 27 | -------------------------------------------------------------------------------- /cmake/cmake_uninstall.cmake.in: -------------------------------------------------------------------------------- 1 | # http://www.vtk.org/Wiki/CMake_FAQ#Can_I_do_.22make_uninstall.22_with_CMake.3F 2 | 3 | IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 4 | MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") 5 | ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") 6 | 7 | FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) 8 | STRING(REGEX REPLACE "\n" ";" files "${files}") 9 | FOREACH(file ${files}) 10 | MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") 11 | IF(EXISTS "$ENV{DESTDIR}${file}") 12 | EXEC_PROGRAM( 13 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 14 | OUTPUT_VARIABLE rm_out 15 | RETURN_VALUE rm_retval 16 | ) 17 | IF(NOT "${rm_retval}" STREQUAL 0) 18 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 19 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 20 | ELSEIF(IS_SYMLINK "$ENV{DESTDIR}${file}") 21 | EXEC_PROGRAM( 22 | "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" 23 | OUTPUT_VARIABLE rm_out 24 | RETURN_VALUE rm_retval 25 | ) 26 | IF(NOT "${rm_retval}" STREQUAL 0) 27 | MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") 28 | ENDIF(NOT "${rm_retval}" STREQUAL 0) 29 | ELSE(EXISTS "$ENV{DESTDIR}${file}") 30 | MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") 31 | ENDIF(EXISTS "$ENV{DESTDIR}${file}") 32 | ENDFOREACH(file) 33 | -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-lazyviterbi 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | 21 | ######################################################################## 22 | # Setup dependencies 23 | ######################################################################## 24 | find_package(Doxygen) 25 | 26 | ######################################################################## 27 | # Begin conditional configuration 28 | ######################################################################## 29 | if(ENABLE_DOXYGEN) 30 | 31 | ######################################################################## 32 | # Add subdirectories 33 | ######################################################################## 34 | add_subdirectory(doxygen) 35 | 36 | endif(ENABLE_DOXYGEN) 37 | -------------------------------------------------------------------------------- /docs/README.lazyviterbi: -------------------------------------------------------------------------------- 1 | This is the lazyviterbi-write-a-block package meant as a guide to building 2 | out-of-tree packages. To use the lazyviterbi blocks, the Python namespaces 3 | is in 'lazyviterbi', which is imported as: 4 | 5 | import lazyviterbi 6 | 7 | See the Doxygen documentation for details about the blocks available 8 | in this package. A quick listing of the details can be found in Python 9 | after importing by using: 10 | 11 | help(lazyviterbi) 12 | -------------------------------------------------------------------------------- /docs/doxygen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-lazyviterbi 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | 21 | ######################################################################## 22 | # Create the doxygen configuration file 23 | ######################################################################## 24 | file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} top_srcdir) 25 | file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} top_builddir) 26 | file(TO_NATIVE_PATH ${CMAKE_SOURCE_DIR} abs_top_srcdir) 27 | file(TO_NATIVE_PATH ${CMAKE_BINARY_DIR} abs_top_builddir) 28 | 29 | set(HAVE_DOT ${DOXYGEN_DOT_FOUND}) 30 | set(enable_html_docs YES) 31 | set(enable_latex_docs NO) 32 | set(enable_xml_docs YES) 33 | 34 | configure_file( 35 | ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in 36 | ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 37 | @ONLY) 38 | 39 | set(BUILT_DIRS ${CMAKE_CURRENT_BINARY_DIR}/xml ${CMAKE_CURRENT_BINARY_DIR}/html) 40 | 41 | ######################################################################## 42 | # Make and install doxygen docs 43 | ######################################################################## 44 | add_custom_command( 45 | OUTPUT ${BUILT_DIRS} 46 | COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile 47 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 48 | COMMENT "Generating documentation with doxygen" 49 | ) 50 | 51 | add_custom_target(doxygen_target ALL DEPENDS ${BUILT_DIRS}) 52 | 53 | install(DIRECTORY ${BUILT_DIRS} DESTINATION ${GR_PKG_DOC_DIR}) 54 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-lazyviterbi 6 | # 7 | # GNU Radio is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 3, or (at your option) 10 | # any later version. 11 | # 12 | # GNU Radio is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with GNU Radio; see the file COPYING. If not, write to 19 | # the Free Software Foundation, Inc., 51 Franklin Street, 20 | # Boston, MA 02110-1301, USA. 21 | # 22 | """ 23 | Python interface to contents of doxygen xml documentation. 24 | 25 | Example use: 26 | See the contents of the example folder for the C++ and 27 | doxygen-generated xml used in this example. 28 | 29 | >>> # Parse the doxygen docs. 30 | >>> import os 31 | >>> this_dir = os.path.dirname(globals()['__file__']) 32 | >>> xml_path = this_dir + "/example/xml/" 33 | >>> di = DoxyIndex(xml_path) 34 | 35 | Get a list of all top-level objects. 36 | 37 | >>> print([mem.name() for mem in di.members()]) 38 | [u'Aadvark', u'aadvarky_enough', u'main'] 39 | 40 | Get all functions. 41 | 42 | >>> print([mem.name() for mem in di.in_category(DoxyFunction)]) 43 | [u'aadvarky_enough', u'main'] 44 | 45 | Check if an object is present. 46 | 47 | >>> di.has_member(u'Aadvark') 48 | True 49 | >>> di.has_member(u'Fish') 50 | False 51 | 52 | Get an item by name and check its properties. 53 | 54 | >>> aad = di.get_member(u'Aadvark') 55 | >>> print(aad.brief_description) 56 | Models the mammal Aadvark. 57 | >>> print(aad.detailed_description) 58 | Sadly the model is incomplete and cannot capture all aspects of an aadvark yet. 59 | 60 | This line is uninformative and is only to test line breaks in the comments. 61 | >>> [mem.name() for mem in aad.members()] 62 | [u'aadvarkness', u'print', u'Aadvark', u'get_aadvarkness'] 63 | >>> aad.get_member(u'print').brief_description 64 | u'Outputs the vital aadvark statistics.' 65 | 66 | """ 67 | from __future__ import unicode_literals 68 | 69 | from .doxyindex import DoxyIndex, DoxyFunction, DoxyParam, DoxyClass, DoxyFile, DoxyNamespace, DoxyGroup, DoxyFriend, DoxyOther 70 | 71 | def _test(): 72 | import os 73 | this_dir = os.path.dirname(globals()['__file__']) 74 | xml_path = this_dir + "/example/xml/" 75 | di = DoxyIndex(xml_path) 76 | # Get the Aadvark class 77 | aad = di.get_member('Aadvark') 78 | aad.brief_description 79 | import doctest 80 | return doctest.testmod() 81 | 82 | if __name__ == "__main__": 83 | _test() 84 | 85 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/base.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-lazyviterbi 6 | # 7 | # GNU Radio is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 3, or (at your option) 10 | # any later version. 11 | # 12 | # GNU Radio is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with GNU Radio; see the file COPYING. If not, write to 19 | # the Free Software Foundation, Inc., 51 Franklin Street, 20 | # Boston, MA 02110-1301, USA. 21 | # 22 | """ 23 | A base class is created. 24 | 25 | Classes based upon this are used to make more user-friendly interfaces 26 | to the doxygen xml docs than the generated classes provide. 27 | """ 28 | from __future__ import print_function 29 | from __future__ import unicode_literals 30 | 31 | import os 32 | import pdb 33 | 34 | from xml.parsers.expat import ExpatError 35 | 36 | from .generated import compound 37 | 38 | 39 | class Base(object): 40 | 41 | class Duplicate(Exception): 42 | pass 43 | 44 | class NoSuchMember(Exception): 45 | pass 46 | 47 | class ParsingError(Exception): 48 | pass 49 | 50 | def __init__(self, parse_data, top=None): 51 | self._parsed = False 52 | self._error = False 53 | self._parse_data = parse_data 54 | self._members = [] 55 | self._dict_members = {} 56 | self._in_category = {} 57 | self._data = {} 58 | if top is not None: 59 | self._xml_path = top._xml_path 60 | # Set up holder of references 61 | else: 62 | top = self 63 | self._refs = {} 64 | self._xml_path = parse_data 65 | self.top = top 66 | 67 | @classmethod 68 | def from_refid(cls, refid, top=None): 69 | """ Instantiate class from a refid rather than parsing object. """ 70 | # First check to see if its already been instantiated. 71 | if top is not None and refid in top._refs: 72 | return top._refs[refid] 73 | # Otherwise create a new instance and set refid. 74 | inst = cls(None, top=top) 75 | inst.refid = refid 76 | inst.add_ref(inst) 77 | return inst 78 | 79 | @classmethod 80 | def from_parse_data(cls, parse_data, top=None): 81 | refid = getattr(parse_data, 'refid', None) 82 | if refid is not None and top is not None and refid in top._refs: 83 | return top._refs[refid] 84 | inst = cls(parse_data, top=top) 85 | if refid is not None: 86 | inst.refid = refid 87 | inst.add_ref(inst) 88 | return inst 89 | 90 | def add_ref(self, obj): 91 | if hasattr(obj, 'refid'): 92 | self.top._refs[obj.refid] = obj 93 | 94 | mem_classes = [] 95 | 96 | def get_cls(self, mem): 97 | for cls in self.mem_classes: 98 | if cls.can_parse(mem): 99 | return cls 100 | raise Exception(("Did not find a class for object '%s'." \ 101 | % (mem.get_name()))) 102 | 103 | def convert_mem(self, mem): 104 | try: 105 | cls = self.get_cls(mem) 106 | converted = cls.from_parse_data(mem, self.top) 107 | if converted is None: 108 | raise Exception('No class matched this object.') 109 | self.add_ref(converted) 110 | return converted 111 | except Exception as e: 112 | print(e) 113 | 114 | @classmethod 115 | def includes(cls, inst): 116 | return isinstance(inst, cls) 117 | 118 | @classmethod 119 | def can_parse(cls, obj): 120 | return False 121 | 122 | def _parse(self): 123 | self._parsed = True 124 | 125 | def _get_dict_members(self, cat=None): 126 | """ 127 | For given category a dictionary is returned mapping member names to 128 | members of that category. For names that are duplicated the name is 129 | mapped to None. 130 | """ 131 | self.confirm_no_error() 132 | if cat not in self._dict_members: 133 | new_dict = {} 134 | for mem in self.in_category(cat): 135 | if mem.name() not in new_dict: 136 | new_dict[mem.name()] = mem 137 | else: 138 | new_dict[mem.name()] = self.Duplicate 139 | self._dict_members[cat] = new_dict 140 | return self._dict_members[cat] 141 | 142 | def in_category(self, cat): 143 | self.confirm_no_error() 144 | if cat is None: 145 | return self._members 146 | if cat not in self._in_category: 147 | self._in_category[cat] = [mem for mem in self._members 148 | if cat.includes(mem)] 149 | return self._in_category[cat] 150 | 151 | def get_member(self, name, cat=None): 152 | self.confirm_no_error() 153 | # Check if it's in a namespace or class. 154 | bits = name.split('::') 155 | first = bits[0] 156 | rest = '::'.join(bits[1:]) 157 | member = self._get_dict_members(cat).get(first, self.NoSuchMember) 158 | # Raise any errors that are returned. 159 | if member in set([self.NoSuchMember, self.Duplicate]): 160 | raise member() 161 | if rest: 162 | return member.get_member(rest, cat=cat) 163 | return member 164 | 165 | def has_member(self, name, cat=None): 166 | try: 167 | mem = self.get_member(name, cat=cat) 168 | return True 169 | except self.NoSuchMember: 170 | return False 171 | 172 | def data(self): 173 | self.confirm_no_error() 174 | return self._data 175 | 176 | def members(self): 177 | self.confirm_no_error() 178 | return self._members 179 | 180 | def process_memberdefs(self): 181 | mdtss = [] 182 | for sec in self._retrieved_data.compounddef.sectiondef: 183 | mdtss += sec.memberdef 184 | # At the moment we lose all information associated with sections. 185 | # Sometimes a memberdef is in several sectiondef. 186 | # We make sure we don't get duplicates here. 187 | uniques = set([]) 188 | for mem in mdtss: 189 | converted = self.convert_mem(mem) 190 | pair = (mem.name, mem.__class__) 191 | if pair not in uniques: 192 | uniques.add(pair) 193 | self._members.append(converted) 194 | 195 | def retrieve_data(self): 196 | filename = os.path.join(self._xml_path, self.refid + '.xml') 197 | try: 198 | self._retrieved_data = compound.parse(filename) 199 | except ExpatError: 200 | print('Error in xml in file %s' % filename) 201 | self._error = True 202 | self._retrieved_data = None 203 | 204 | def check_parsed(self): 205 | if not self._parsed: 206 | self._parse() 207 | 208 | def confirm_no_error(self): 209 | self.check_parsed() 210 | if self._error: 211 | raise self.ParsingError() 212 | 213 | def error(self): 214 | self.check_parsed() 215 | return self._error 216 | 217 | def name(self): 218 | # first see if we can do it without processing. 219 | if self._parse_data is not None: 220 | return self._parse_data.name 221 | self.check_parsed() 222 | return self._retrieved_data.compounddef.name 223 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/doxyindex.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-lazyviterbi 6 | # 7 | # GNU Radio is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 3, or (at your option) 10 | # any later version. 11 | # 12 | # GNU Radio is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with GNU Radio; see the file COPYING. If not, write to 19 | # the Free Software Foundation, Inc., 51 Franklin Street, 20 | # Boston, MA 02110-1301, USA. 21 | # 22 | """ 23 | Classes providing more user-friendly interfaces to the doxygen xml 24 | docs than the generated classes provide. 25 | """ 26 | from __future__ import absolute_import 27 | from __future__ import unicode_literals 28 | 29 | import os 30 | 31 | from .generated import index 32 | from .base import Base 33 | from .text import description 34 | 35 | class DoxyIndex(Base): 36 | """ 37 | Parses a doxygen xml directory. 38 | """ 39 | 40 | __module__ = "gnuradio.utils.doxyxml" 41 | 42 | def _parse(self): 43 | if self._parsed: 44 | return 45 | super(DoxyIndex, self)._parse() 46 | self._root = index.parse(os.path.join(self._xml_path, 'index.xml')) 47 | for mem in self._root.compound: 48 | converted = self.convert_mem(mem) 49 | # For files and namespaces we want the contents to be 50 | # accessible directly from the parent rather than having 51 | # to go through the file object. 52 | if self.get_cls(mem) == DoxyFile: 53 | if mem.name.endswith('.h'): 54 | self._members += converted.members() 55 | self._members.append(converted) 56 | elif self.get_cls(mem) == DoxyNamespace: 57 | self._members += converted.members() 58 | self._members.append(converted) 59 | else: 60 | self._members.append(converted) 61 | 62 | 63 | def generate_swig_doc_i(self): 64 | """ 65 | %feature("docstring") gr_make_align_on_samplenumbers_ss::align_state " 66 | Wraps the C++: gr_align_on_samplenumbers_ss::align_state"; 67 | """ 68 | pass 69 | 70 | 71 | class DoxyCompMem(Base): 72 | 73 | 74 | kind = None 75 | 76 | def __init__(self, *args, **kwargs): 77 | super(DoxyCompMem, self).__init__(*args, **kwargs) 78 | 79 | @classmethod 80 | def can_parse(cls, obj): 81 | return obj.kind == cls.kind 82 | 83 | def set_descriptions(self, parse_data): 84 | bd = description(getattr(parse_data, 'briefdescription', None)) 85 | dd = description(getattr(parse_data, 'detaileddescription', None)) 86 | self._data['brief_description'] = bd 87 | self._data['detailed_description'] = dd 88 | 89 | def set_parameters(self, data): 90 | vs = [ddc.value for ddc in data.detaileddescription.content_] 91 | pls = [] 92 | for v in vs: 93 | if hasattr(v, 'parameterlist'): 94 | pls += v.parameterlist 95 | pis = [] 96 | for pl in pls: 97 | pis += pl.parameteritem 98 | dpis = [] 99 | for pi in pis: 100 | dpi = DoxyParameterItem(pi) 101 | dpi._parse() 102 | dpis.append(dpi) 103 | self._data['params'] = dpis 104 | 105 | 106 | class DoxyCompound(DoxyCompMem): 107 | pass 108 | 109 | class DoxyMember(DoxyCompMem): 110 | pass 111 | 112 | class DoxyFunction(DoxyMember): 113 | 114 | __module__ = "gnuradio.utils.doxyxml" 115 | 116 | kind = 'function' 117 | 118 | def _parse(self): 119 | if self._parsed: 120 | return 121 | super(DoxyFunction, self)._parse() 122 | self.set_descriptions(self._parse_data) 123 | self.set_parameters(self._parse_data) 124 | if not self._data['params']: 125 | # If the params weren't set by a comment then just grab the names. 126 | self._data['params'] = [] 127 | prms = self._parse_data.param 128 | for prm in prms: 129 | self._data['params'].append(DoxyParam(prm)) 130 | 131 | brief_description = property(lambda self: self.data()['brief_description']) 132 | detailed_description = property(lambda self: self.data()['detailed_description']) 133 | params = property(lambda self: self.data()['params']) 134 | 135 | Base.mem_classes.append(DoxyFunction) 136 | 137 | 138 | class DoxyParam(DoxyMember): 139 | 140 | __module__ = "gnuradio.utils.doxyxml" 141 | 142 | def _parse(self): 143 | if self._parsed: 144 | return 145 | super(DoxyParam, self)._parse() 146 | self.set_descriptions(self._parse_data) 147 | self._data['declname'] = self._parse_data.declname 148 | 149 | @property 150 | def description(self): 151 | descriptions = [] 152 | if self.brief_description: 153 | descriptions.append(self.brief_description) 154 | if self.detailed_description: 155 | descriptions.append(self.detailed_description) 156 | return '\n\n'.join(descriptions) 157 | 158 | brief_description = property(lambda self: self.data()['brief_description']) 159 | detailed_description = property(lambda self: self.data()['detailed_description']) 160 | name = property(lambda self: self.data()['declname']) 161 | 162 | class DoxyParameterItem(DoxyMember): 163 | """A different representation of a parameter in Doxygen.""" 164 | 165 | def _parse(self): 166 | if self._parsed: 167 | return 168 | super(DoxyParameterItem, self)._parse() 169 | names = [] 170 | for nl in self._parse_data.parameternamelist: 171 | for pn in nl.parametername: 172 | names.append(description(pn)) 173 | # Just take first name 174 | self._data['name'] = names[0] 175 | # Get description 176 | pd = description(self._parse_data.get_parameterdescription()) 177 | self._data['description'] = pd 178 | 179 | description = property(lambda self: self.data()['description']) 180 | name = property(lambda self: self.data()['name']) 181 | 182 | 183 | class DoxyClass(DoxyCompound): 184 | 185 | __module__ = "gnuradio.utils.doxyxml" 186 | 187 | kind = 'class' 188 | 189 | def _parse(self): 190 | if self._parsed: 191 | return 192 | super(DoxyClass, self)._parse() 193 | self.retrieve_data() 194 | if self._error: 195 | return 196 | self.set_descriptions(self._retrieved_data.compounddef) 197 | self.set_parameters(self._retrieved_data.compounddef) 198 | # Sectiondef.kind tells about whether private or public. 199 | # We just ignore this for now. 200 | self.process_memberdefs() 201 | 202 | brief_description = property(lambda self: self.data()['brief_description']) 203 | detailed_description = property(lambda self: self.data()['detailed_description']) 204 | params = property(lambda self: self.data()['params']) 205 | 206 | Base.mem_classes.append(DoxyClass) 207 | 208 | 209 | class DoxyFile(DoxyCompound): 210 | 211 | __module__ = "gnuradio.utils.doxyxml" 212 | 213 | kind = 'file' 214 | 215 | def _parse(self): 216 | if self._parsed: 217 | return 218 | super(DoxyFile, self)._parse() 219 | self.retrieve_data() 220 | self.set_descriptions(self._retrieved_data.compounddef) 221 | if self._error: 222 | return 223 | self.process_memberdefs() 224 | 225 | brief_description = property(lambda self: self.data()['brief_description']) 226 | detailed_description = property(lambda self: self.data()['detailed_description']) 227 | 228 | Base.mem_classes.append(DoxyFile) 229 | 230 | 231 | class DoxyNamespace(DoxyCompound): 232 | 233 | __module__ = "gnuradio.utils.doxyxml" 234 | 235 | kind = 'namespace' 236 | 237 | def _parse(self): 238 | if self._parsed: 239 | return 240 | super(DoxyNamespace, self)._parse() 241 | self.retrieve_data() 242 | self.set_descriptions(self._retrieved_data.compounddef) 243 | if self._error: 244 | return 245 | self.process_memberdefs() 246 | 247 | Base.mem_classes.append(DoxyNamespace) 248 | 249 | 250 | class DoxyGroup(DoxyCompound): 251 | 252 | __module__ = "gnuradio.utils.doxyxml" 253 | 254 | kind = 'group' 255 | 256 | def _parse(self): 257 | if self._parsed: 258 | return 259 | super(DoxyGroup, self)._parse() 260 | self.retrieve_data() 261 | if self._error: 262 | return 263 | cdef = self._retrieved_data.compounddef 264 | self._data['title'] = description(cdef.title) 265 | # Process inner groups 266 | grps = cdef.innergroup 267 | for grp in grps: 268 | converted = DoxyGroup.from_refid(grp.refid, top=self.top) 269 | self._members.append(converted) 270 | # Process inner classes 271 | klasses = cdef.innerclass 272 | for kls in klasses: 273 | converted = DoxyClass.from_refid(kls.refid, top=self.top) 274 | self._members.append(converted) 275 | # Process normal members 276 | self.process_memberdefs() 277 | 278 | title = property(lambda self: self.data()['title']) 279 | 280 | 281 | Base.mem_classes.append(DoxyGroup) 282 | 283 | 284 | class DoxyFriend(DoxyMember): 285 | 286 | __module__ = "gnuradio.utils.doxyxml" 287 | 288 | kind = 'friend' 289 | 290 | Base.mem_classes.append(DoxyFriend) 291 | 292 | 293 | class DoxyOther(Base): 294 | 295 | __module__ = "gnuradio.utils.doxyxml" 296 | 297 | kinds = set(['variable', 'struct', 'union', 'define', 'typedef', 'enum', 298 | 'dir', 'page', 'signal', 'slot', 'property']) 299 | 300 | @classmethod 301 | def can_parse(cls, obj): 302 | return obj.kind in cls.kinds 303 | 304 | Base.mem_classes.append(DoxyOther) 305 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Contains generated files produced by generateDS.py. 3 | 4 | These do the real work of parsing the doxygen xml files but the 5 | resultant classes are not very friendly to navigate so the rest of the 6 | doxyxml module processes them further. 7 | """ 8 | from __future__ import unicode_literals 9 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/generated/index.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Generated Mon Feb 9 19:08:05 2009 by generateDS.py. 5 | """ 6 | from __future__ import absolute_import 7 | from __future__ import unicode_literals 8 | 9 | from xml.dom import minidom 10 | 11 | import os 12 | import sys 13 | from . import compound 14 | 15 | from . import indexsuper as supermod 16 | 17 | class DoxygenTypeSub(supermod.DoxygenType): 18 | def __init__(self, version=None, compound=None): 19 | supermod.DoxygenType.__init__(self, version, compound) 20 | 21 | def find_compounds_and_members(self, details): 22 | """ 23 | Returns a list of all compounds and their members which match details 24 | """ 25 | 26 | results = [] 27 | for compound in self.compound: 28 | members = compound.find_members(details) 29 | if members: 30 | results.append([compound, members]) 31 | else: 32 | if details.match(compound): 33 | results.append([compound, []]) 34 | 35 | return results 36 | 37 | supermod.DoxygenType.subclass = DoxygenTypeSub 38 | # end class DoxygenTypeSub 39 | 40 | 41 | class CompoundTypeSub(supermod.CompoundType): 42 | def __init__(self, kind=None, refid=None, name='', member=None): 43 | supermod.CompoundType.__init__(self, kind, refid, name, member) 44 | 45 | def find_members(self, details): 46 | """ 47 | Returns a list of all members which match details 48 | """ 49 | 50 | results = [] 51 | 52 | for member in self.member: 53 | if details.match(member): 54 | results.append(member) 55 | 56 | return results 57 | 58 | supermod.CompoundType.subclass = CompoundTypeSub 59 | # end class CompoundTypeSub 60 | 61 | 62 | class MemberTypeSub(supermod.MemberType): 63 | 64 | def __init__(self, kind=None, refid=None, name=''): 65 | supermod.MemberType.__init__(self, kind, refid, name) 66 | 67 | supermod.MemberType.subclass = MemberTypeSub 68 | # end class MemberTypeSub 69 | 70 | 71 | def parse(inFilename): 72 | 73 | doc = minidom.parse(inFilename) 74 | rootNode = doc.documentElement 75 | rootObj = supermod.DoxygenType.factory() 76 | rootObj.build(rootNode) 77 | 78 | return rootObj 79 | 80 | -------------------------------------------------------------------------------- /docs/doxygen/doxyxml/text.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-lazyviterbi 6 | # 7 | # GNU Radio is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 3, or (at your option) 10 | # any later version. 11 | # 12 | # GNU Radio is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with GNU Radio; see the file COPYING. If not, write to 19 | # the Free Software Foundation, Inc., 51 Franklin Street, 20 | # Boston, MA 02110-1301, USA. 21 | # 22 | """ 23 | Utilities for extracting text from generated classes. 24 | """ 25 | from __future__ import unicode_literals 26 | 27 | def is_string(txt): 28 | if isinstance(txt, str): 29 | return True 30 | try: 31 | if isinstance(txt, str): 32 | return True 33 | except NameError: 34 | pass 35 | return False 36 | 37 | def description(obj): 38 | if obj is None: 39 | return None 40 | return description_bit(obj).strip() 41 | 42 | def description_bit(obj): 43 | if hasattr(obj, 'content'): 44 | contents = [description_bit(item) for item in obj.content] 45 | result = ''.join(contents) 46 | elif hasattr(obj, 'content_'): 47 | contents = [description_bit(item) for item in obj.content_] 48 | result = ''.join(contents) 49 | elif hasattr(obj, 'value'): 50 | result = description_bit(obj.value) 51 | elif is_string(obj): 52 | return obj 53 | else: 54 | raise Exception('Expecting a string or something with content, content_ or value attribute') 55 | # If this bit is a paragraph then add one some line breaks. 56 | if hasattr(obj, 'name') and obj.name == 'para': 57 | result += "\n\n" 58 | return result 59 | -------------------------------------------------------------------------------- /docs/doxygen/other/group_defs.dox: -------------------------------------------------------------------------------- 1 | /*! 2 | * \defgroup block GNU Radio LAZYVITERBI C++ Signal Processing Blocks 3 | * \brief All C++ blocks that can be used from the LAZYVITERBI GNU Radio 4 | * module are listed here or in the subcategories below. 5 | * 6 | */ 7 | 8 | -------------------------------------------------------------------------------- /docs/doxygen/other/main_page.dox: -------------------------------------------------------------------------------- 1 | /*! \mainpage 2 | 3 | Welcome to the GNU Radio LAZYVITERBI Block 4 | 5 | This is the intro page for the Doxygen manual generated for the LAZYVITERBI 6 | block (docs/doxygen/other/main_page.dox). Edit it to add more detailed 7 | documentation about the new GNU Radio modules contained in this 8 | project. 9 | 10 | */ 11 | -------------------------------------------------------------------------------- /docs/doxygen/swig_doc.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2010-2012 Free Software Foundation, Inc. 3 | # 4 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 5 | # This file is a part of gr-lazyviterbi 6 | # 7 | # GNU Radio is free software; you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation; either version 3, or (at your option) 10 | # any later version. 11 | # 12 | # GNU Radio is distributed in the hope that it will be useful, 13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | # GNU General Public License for more details. 16 | # 17 | # You should have received a copy of the GNU General Public License 18 | # along with GNU Radio; see the file COPYING. If not, write to 19 | # the Free Software Foundation, Inc., 51 Franklin Street, 20 | # Boston, MA 02110-1301, USA. 21 | # 22 | """ 23 | Creates the swig_doc.i SWIG interface file. 24 | Execute using: python swig_doc.py xml_path outputfilename 25 | 26 | The file instructs SWIG to transfer the doxygen comments into the 27 | python docstrings. 28 | 29 | """ 30 | from __future__ import unicode_literals 31 | 32 | import sys, time 33 | 34 | from doxyxml import DoxyIndex, DoxyClass, DoxyFriend, DoxyFunction, DoxyFile 35 | from doxyxml import DoxyOther, base 36 | 37 | def py_name(name): 38 | bits = name.split('_') 39 | return '_'.join(bits[1:]) 40 | 41 | def make_name(name): 42 | bits = name.split('_') 43 | return bits[0] + '_make_' + '_'.join(bits[1:]) 44 | 45 | 46 | class Block(object): 47 | """ 48 | Checks if doxyxml produced objects correspond to a gnuradio block. 49 | """ 50 | 51 | @classmethod 52 | def includes(cls, item): 53 | if not isinstance(item, DoxyClass): 54 | return False 55 | # Check for a parsing error. 56 | if item.error(): 57 | return False 58 | friendname = make_name(item.name()) 59 | is_a_block = item.has_member(friendname, DoxyFriend) 60 | # But now sometimes the make function isn't a friend so check again. 61 | if not is_a_block: 62 | is_a_block = di.has_member(friendname, DoxyFunction) 63 | return is_a_block 64 | 65 | class Block2(object): 66 | """ 67 | Checks if doxyxml produced objects correspond to a new style 68 | gnuradio block. 69 | """ 70 | 71 | @classmethod 72 | def includes(cls, item): 73 | if not isinstance(item, DoxyClass): 74 | return False 75 | # Check for a parsing error. 76 | if item.error(): 77 | return False 78 | is_a_block2 = item.has_member('make', DoxyFunction) and item.has_member('sptr', DoxyOther) 79 | return is_a_block2 80 | 81 | 82 | def utoascii(text): 83 | """ 84 | Convert unicode text into ascii and escape quotes and backslashes. 85 | """ 86 | if text is None: 87 | return '' 88 | out = text.encode('ascii', 'replace') 89 | # swig will require us to replace blackslash with 4 backslashes 90 | out = out.replace(b'\\', b'\\\\\\\\') 91 | out = out.replace(b'"', b'\\"').decode('ascii') 92 | return str(out) 93 | 94 | 95 | def combine_descriptions(obj): 96 | """ 97 | Combines the brief and detailed descriptions of an object together. 98 | """ 99 | description = [] 100 | bd = obj.brief_description.strip() 101 | dd = obj.detailed_description.strip() 102 | if bd: 103 | description.append(bd) 104 | if dd: 105 | description.append(dd) 106 | return utoascii('\n\n'.join(description)).strip() 107 | 108 | def format_params(parameteritems): 109 | output = ['Args:'] 110 | template = ' {0} : {1}' 111 | for pi in parameteritems: 112 | output.append(template.format(pi.name, pi.description)) 113 | return '\n'.join(output) 114 | 115 | entry_templ = '%feature("docstring") {name} "{docstring}"' 116 | def make_entry(obj, name=None, templ="{description}", description=None, params=[]): 117 | """ 118 | Create a docstring entry for a swig interface file. 119 | 120 | obj - a doxyxml object from which documentation will be extracted. 121 | name - the name of the C object (defaults to obj.name()) 122 | templ - an optional template for the docstring containing only one 123 | variable named 'description'. 124 | description - if this optional variable is set then it's value is 125 | used as the description instead of extracting it from obj. 126 | """ 127 | if name is None: 128 | name=obj.name() 129 | if "operator " in name: 130 | return '' 131 | if description is None: 132 | description = combine_descriptions(obj) 133 | if params: 134 | description += '\n\n' 135 | description += utoascii(format_params(params)) 136 | docstring = templ.format(description=description) 137 | if not docstring: 138 | return '' 139 | return entry_templ.format( 140 | name=name, 141 | docstring=docstring, 142 | ) 143 | 144 | 145 | def make_func_entry(func, name=None, description=None, params=None): 146 | """ 147 | Create a function docstring entry for a swig interface file. 148 | 149 | func - a doxyxml object from which documentation will be extracted. 150 | name - the name of the C object (defaults to func.name()) 151 | description - if this optional variable is set then it's value is 152 | used as the description instead of extracting it from func. 153 | params - a parameter list that overrides using func.params. 154 | """ 155 | #if params is None: 156 | # params = func.params 157 | #params = [prm.declname for prm in params] 158 | #if params: 159 | # sig = "Params: (%s)" % ", ".join(params) 160 | #else: 161 | # sig = "Params: (NONE)" 162 | #templ = "{description}\n\n" + sig 163 | #return make_entry(func, name=name, templ=utoascii(templ), 164 | # description=description) 165 | return make_entry(func, name=name, description=description, params=params) 166 | 167 | 168 | def make_class_entry(klass, description=None, ignored_methods=[], params=None): 169 | """ 170 | Create a class docstring for a swig interface file. 171 | """ 172 | if params is None: 173 | params = klass.params 174 | output = [] 175 | output.append(make_entry(klass, description=description, params=params)) 176 | for func in klass.in_category(DoxyFunction): 177 | if func.name() not in ignored_methods: 178 | name = klass.name() + '::' + func.name() 179 | output.append(make_func_entry(func, name=name)) 180 | return "\n\n".join(output) 181 | 182 | 183 | def make_block_entry(di, block): 184 | """ 185 | Create class and function docstrings of a gnuradio block for a 186 | swig interface file. 187 | """ 188 | descriptions = [] 189 | # Get the documentation associated with the class. 190 | class_desc = combine_descriptions(block) 191 | if class_desc: 192 | descriptions.append(class_desc) 193 | # Get the documentation associated with the make function 194 | make_func = di.get_member(make_name(block.name()), DoxyFunction) 195 | make_func_desc = combine_descriptions(make_func) 196 | if make_func_desc: 197 | descriptions.append(make_func_desc) 198 | # Get the documentation associated with the file 199 | try: 200 | block_file = di.get_member(block.name() + ".h", DoxyFile) 201 | file_desc = combine_descriptions(block_file) 202 | if file_desc: 203 | descriptions.append(file_desc) 204 | except base.Base.NoSuchMember: 205 | # Don't worry if we can't find a matching file. 206 | pass 207 | # And join them all together to make a super duper description. 208 | super_description = "\n\n".join(descriptions) 209 | # Associate the combined description with the class and 210 | # the make function. 211 | output = [] 212 | output.append(make_class_entry(block, description=super_description)) 213 | output.append(make_func_entry(make_func, description=super_description, 214 | params=block.params)) 215 | return "\n\n".join(output) 216 | 217 | def make_block2_entry(di, block): 218 | """ 219 | Create class and function docstrings of a new style gnuradio block for a 220 | swig interface file. 221 | """ 222 | descriptions = [] 223 | # For new style blocks all the relevant documentation should be 224 | # associated with the 'make' method. 225 | class_description = combine_descriptions(block) 226 | make_func = block.get_member('make', DoxyFunction) 227 | make_description = combine_descriptions(make_func) 228 | description = class_description + "\n\nConstructor Specific Documentation:\n\n" + make_description 229 | # Associate the combined description with the class and 230 | # the make function. 231 | output = [] 232 | output.append(make_class_entry( 233 | block, description=description, 234 | ignored_methods=['make'], params=make_func.params)) 235 | makename = block.name() + '::make' 236 | output.append(make_func_entry( 237 | make_func, name=makename, description=description, 238 | params=make_func.params)) 239 | return "\n\n".join(output) 240 | 241 | def make_swig_interface_file(di, swigdocfilename, custom_output=None): 242 | 243 | output = [""" 244 | /* 245 | * This file was automatically generated using swig_doc.py. 246 | * 247 | * Any changes to it will be lost next time it is regenerated. 248 | */ 249 | """] 250 | 251 | if custom_output is not None: 252 | output.append(custom_output) 253 | 254 | # Create docstrings for the blocks. 255 | blocks = di.in_category(Block) 256 | blocks2 = di.in_category(Block2) 257 | 258 | make_funcs = set([]) 259 | for block in blocks: 260 | try: 261 | make_func = di.get_member(make_name(block.name()), DoxyFunction) 262 | # Don't want to risk writing to output twice. 263 | if make_func.name() not in make_funcs: 264 | make_funcs.add(make_func.name()) 265 | output.append(make_block_entry(di, block)) 266 | except block.ParsingError: 267 | sys.stderr.write('Parsing error for block {0}\n'.format(block.name())) 268 | raise 269 | 270 | for block in blocks2: 271 | try: 272 | make_func = block.get_member('make', DoxyFunction) 273 | make_func_name = block.name() +'::make' 274 | # Don't want to risk writing to output twice. 275 | if make_func_name not in make_funcs: 276 | make_funcs.add(make_func_name) 277 | output.append(make_block2_entry(di, block)) 278 | except block.ParsingError: 279 | sys.stderr.write('Parsing error for block {0}\n'.format(block.name())) 280 | raise 281 | 282 | # Create docstrings for functions 283 | # Don't include the make functions since they have already been dealt with. 284 | funcs = [f for f in di.in_category(DoxyFunction) 285 | if f.name() not in make_funcs and not f.name().startswith('std::')] 286 | for f in funcs: 287 | try: 288 | output.append(make_func_entry(f)) 289 | except f.ParsingError: 290 | sys.stderr.write('Parsing error for function {0}\n'.format(f.name())) 291 | 292 | # Create docstrings for classes 293 | block_names = [block.name() for block in blocks] 294 | block_names += [block.name() for block in blocks2] 295 | klasses = [k for k in di.in_category(DoxyClass) 296 | if k.name() not in block_names and not k.name().startswith('std::')] 297 | for k in klasses: 298 | try: 299 | output.append(make_class_entry(k)) 300 | except k.ParsingError: 301 | sys.stderr.write('Parsing error for class {0}\n'.format(k.name())) 302 | 303 | # Docstrings are not created for anything that is not a function or a class. 304 | # If this excludes anything important please add it here. 305 | 306 | output = "\n\n".join(output) 307 | 308 | swig_doc = open(swigdocfilename, 'w') 309 | swig_doc.write(output) 310 | swig_doc.close() 311 | 312 | if __name__ == "__main__": 313 | # Parse command line options and set up doxyxml. 314 | err_msg = "Execute using: python swig_doc.py xml_path outputfilename" 315 | if len(sys.argv) != 3: 316 | raise Exception(err_msg) 317 | xml_path = sys.argv[1] 318 | swigdocfilename = sys.argv[2] 319 | di = DoxyIndex(xml_path) 320 | 321 | # gnuradio.gr.msq_queue.insert_tail and delete_head create errors unless docstrings are defined! 322 | # This is presumably a bug in SWIG. 323 | #msg_q = di.get_member(u'gr_msg_queue', DoxyClass) 324 | #insert_tail = msg_q.get_member(u'insert_tail', DoxyFunction) 325 | #delete_head = msg_q.get_member(u'delete_head', DoxyFunction) 326 | output = [] 327 | #output.append(make_func_entry(insert_tail, name='gr_py_msg_queue__insert_tail')) 328 | #output.append(make_func_entry(delete_head, name='gr_py_msg_queue__delete_head')) 329 | custom_output = "\n\n".join(output) 330 | 331 | # Generate the docstrings interface file. 332 | make_swig_interface_file(di, swigdocfilename, custom_output=custom_output) 333 | -------------------------------------------------------------------------------- /examples/README: -------------------------------------------------------------------------------- 1 | It is considered good practice to add examples in here to demonstrate the 2 | functionality of your OOT module. Python scripts, GRC flow graphs or other 3 | code can go here. 4 | 5 | -------------------------------------------------------------------------------- /examples/ber_vs_ebn0_75_awgn.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | 4 | from gnuradio import analog 5 | from gnuradio import blocks 6 | from gnuradio import digital 7 | from gnuradio import gr 8 | from gnuradio import trellis 9 | from gnuradio import fec 10 | import lazyviterbi as lv 11 | 12 | import os 13 | import numpy 14 | import matplotlib.pyplot as plt 15 | 16 | 17 | class ber_vs_ebn0_awgn(gr.top_block): 18 | 19 | def __init__(self, pkt_len, nb_pkt, EbN0dB): 20 | gr.top_block.__init__(self, "BER vs Eb/N0 (7,5) AWGN") 21 | 22 | ################################################## 23 | # Variables 24 | ################################################## 25 | self.prefix = prefix = os.getcwd() 26 | self.pkt_len = pkt_len 27 | #self.fsm = fsm = trellis.fsm(prefix + "/fsm/229_159.fsm") 28 | #self.fsm = fsm = trellis.fsm(prefix + "/fsm/rsc_15_13.fsm") 29 | #self.fsm = fsm = trellis.fsm(prefix + "/fsm/171_133.fsm") 30 | self.fsm = fsm = trellis.fsm(prefix + "/fsm/5_7.fsm") 31 | Rc=0.5 32 | self.const = const = digital.constellation_bpsk().base() 33 | 34 | var_c=1 35 | Nb=1 36 | Eb=var_c/(2.0*Nb*Rc) 37 | N0=Eb * 10**(-EbN0dB/10.0) 38 | noisevar=2*N0 39 | 40 | ################################################## 41 | # Blocks 42 | ################################################## 43 | self.bits_src = blocks.vector_source_b(numpy.random.randint(0, 2, nb_pkt*pkt_len), False) 44 | self.trellis_encoder = trellis.encoder_bb(trellis.fsm(fsm), 0, pkt_len) 45 | self.unpack = blocks.unpack_k_bits_bb(2) 46 | self.pack_src = blocks.pack_k_bits_bb(8) 47 | self.to_symbols = digital.chunks_to_symbols_bc((const.points()), 1) 48 | 49 | self.noise_src = analog.noise_source_c(analog.GR_GAUSSIAN, noisevar, 0) 50 | self.noise_adder = blocks.add_vcc(1) 51 | 52 | self.metrics_computer = trellis.metrics_c(4, 2, ([-1, -1, -1, 1, 1, -1, 1, 1]), digital.TRELLIS_EUCLIDEAN) 53 | 54 | self.trellis_viterbi = trellis.viterbi_b(trellis.fsm(fsm), pkt_len, 0, -1) 55 | self.viterbi = lv.viterbi(trellis.fsm(fsm), pkt_len, 0, -1) 56 | self.lazy = lv.lazy_viterbi(trellis.fsm(fsm), pkt_len, 0, -1) 57 | self.viterbi_vb = lv.viterbi_volk_branch(trellis.fsm(fsm), pkt_len, 0, -1) 58 | self.viterbi_vs = lv.viterbi_volk_state(trellis.fsm(fsm), pkt_len, 0, -1) 59 | 60 | self.pack_trellis_viterbi = blocks.pack_k_bits_bb(8) 61 | self.pack_viterbi = blocks.pack_k_bits_bb(8) 62 | self.pack_lazy = blocks.pack_k_bits_bb(8) 63 | self.pack_viterbi_vb = blocks.pack_k_bits_bb(8) 64 | self.pack_viterbi_vs = blocks.pack_k_bits_bb(8) 65 | 66 | self.ber_computer_trellis_viterbi = fec.ber_bf(False) 67 | self.ber_computer_viterbi = fec.ber_bf(False) 68 | self.ber_computer_lazy = fec.ber_bf(False) 69 | self.ber_computer_viterbi_vb = fec.ber_bf(False) 70 | self.ber_computer_viterbi_vs = fec.ber_bf(False) 71 | 72 | self.vector_sink_trellis_viterbi = blocks.vector_sink_f() 73 | self.vector_sink_viterbi = blocks.vector_sink_f() 74 | self.vector_sink_lazy = blocks.vector_sink_f() 75 | self.vector_sink_viterbi_vb = blocks.vector_sink_f() 76 | self.vector_sink_viterbi_vs = blocks.vector_sink_f() 77 | 78 | ################################################## 79 | # Connections 80 | ################################################## 81 | 82 | self.connect((self.bits_src, 0), (self.trellis_encoder, 0)) 83 | self.connect((self.trellis_encoder, 0), (self.unpack, 0)) 84 | self.connect((self.unpack, 0), (self.to_symbols, 0)) 85 | 86 | self.connect((self.to_symbols, 0), (self.noise_adder, 0)) 87 | self.connect((self.noise_src, 0), (self.noise_adder, 1)) 88 | self.connect((self.noise_adder, 0), (self.metrics_computer, 0)) 89 | 90 | self.connect((self.metrics_computer, 0), (self.trellis_viterbi, 0)) 91 | self.connect((self.metrics_computer, 0), (self.viterbi, 0)) 92 | self.connect((self.metrics_computer, 0), (self.lazy, 0)) 93 | self.connect((self.metrics_computer, 0), (self.viterbi_vb, 0)) 94 | self.connect((self.metrics_computer, 0), (self.viterbi_vs, 0)) 95 | 96 | self.connect((self.bits_src, 0), (self.pack_src, 0)) 97 | self.connect((self.trellis_viterbi, 0), (self.pack_trellis_viterbi, 0)) 98 | self.connect((self.viterbi, 0), (self.pack_viterbi, 0)) 99 | self.connect((self.lazy, 0), (self.pack_lazy, 0)) 100 | self.connect((self.viterbi_vb, 0), (self.pack_viterbi_vb, 0)) 101 | self.connect((self.viterbi_vs, 0), (self.pack_viterbi_vs, 0)) 102 | 103 | self.connect((self.pack_src, 0), (self.ber_computer_trellis_viterbi, 0)) 104 | self.connect((self.pack_src, 0), (self.ber_computer_viterbi, 0)) 105 | self.connect((self.pack_src, 0), (self.ber_computer_lazy, 0)) 106 | self.connect((self.pack_src, 0), (self.ber_computer_viterbi_vb, 0)) 107 | self.connect((self.pack_src, 0), (self.ber_computer_viterbi_vs, 0)) 108 | 109 | self.connect((self.pack_trellis_viterbi, 0), (self.ber_computer_trellis_viterbi, 1)) 110 | self.connect((self.pack_viterbi, 0), (self.ber_computer_viterbi, 1)) 111 | self.connect((self.pack_lazy, 0), (self.ber_computer_lazy, 1)) 112 | self.connect((self.pack_viterbi_vb, 0), (self.ber_computer_viterbi_vb, 1)) 113 | self.connect((self.pack_viterbi_vs, 0), (self.ber_computer_viterbi_vs, 1)) 114 | 115 | self.connect((self.ber_computer_trellis_viterbi, 0), (self.vector_sink_trellis_viterbi, 0)) 116 | self.connect((self.ber_computer_viterbi, 0), (self.vector_sink_viterbi, 0)) 117 | self.connect((self.ber_computer_lazy, 0), (self.vector_sink_lazy, 0)) 118 | self.connect((self.ber_computer_viterbi_vb, 0), (self.vector_sink_viterbi_vb, 0)) 119 | self.connect((self.ber_computer_viterbi_vs, 0), (self.vector_sink_viterbi_vs, 0)) 120 | 121 | def main(): 122 | pkt_len = 16384 123 | nb_pkt=100 124 | #EbN0dB = [10] 125 | EbN0dB = numpy.linspace(0, 10, 11) 126 | BER_trellis_viterbi = numpy.zeros(len(EbN0dB)) 127 | BER_viterbi = numpy.zeros(len(EbN0dB)) 128 | BER_lazy = numpy.zeros(len(EbN0dB)) 129 | BER_viterbi_vb = numpy.zeros(len(EbN0dB)) 130 | BER_viterbi_vs = numpy.zeros(len(EbN0dB)) 131 | 132 | for i in range(0, len(EbN0dB)): 133 | print("Eb/N0=" + str(EbN0dB[i])) 134 | 135 | tb = ber_vs_ebn0_awgn(pkt_len, nb_pkt, EbN0dB[i]) 136 | tb.run() 137 | 138 | print("BER Viterbi (gr-trellis):" + str(tb.vector_sink_trellis_viterbi.data())) 139 | BER_trellis_viterbi[i] = 10**(numpy.mean(tb.vector_sink_trellis_viterbi.data())) 140 | tb.vector_sink_trellis_viterbi.reset() 141 | 142 | print("BER Viterbi (gr-lazyviterbi):" + str(tb.vector_sink_viterbi.data())) 143 | BER_viterbi[i] = 10**(numpy.mean(tb.vector_sink_viterbi.data())) 144 | tb.vector_sink_viterbi.reset() 145 | 146 | print("BER Lazy:" + str(tb.vector_sink_lazy.data())) 147 | BER_lazy[i] = 10**(numpy.mean(tb.vector_sink_lazy.data())) 148 | tb.vector_sink_lazy.reset() 149 | 150 | print("BER Viterbi volk branch:" + str(tb.vector_sink_viterbi_vb.data())) 151 | BER_viterbi_vb[i] = 10**(numpy.mean(tb.vector_sink_viterbi_vb.data())) 152 | tb.vector_sink_viterbi.reset() 153 | 154 | print("BER Viterbi volk state:" + str(tb.vector_sink_viterbi_vs.data())) 155 | BER_viterbi_vs[i] = 10**(numpy.mean(tb.vector_sink_viterbi_vs.data())) 156 | tb.vector_sink_viterbi.reset() 157 | 158 | print("") 159 | 160 | #Plot results 161 | plt.semilogy(EbN0dB, BER_trellis_viterbi, '-*', 162 | label="Viterbi (gr-trellis)") 163 | plt.semilogy(EbN0dB, BER_viterbi, '-+', label="Viterbi (gr-lazyviterbi)") 164 | plt.semilogy(EbN0dB, BER_lazy, '-x', label="Lazy") 165 | plt.semilogy(EbN0dB, BER_viterbi_vb, '-o', label="Viterbi volk branch") 166 | plt.semilogy(EbN0dB, BER_viterbi_vs, '-.', label="Viterbi volk state") 167 | 168 | plt.grid(which='both') 169 | plt.ylabel('BER') 170 | plt.xlabel('Eb/N0 (dB)') 171 | plt.legend() 172 | plt.show() 173 | 174 | if __name__ == '__main__': 175 | main() 176 | -------------------------------------------------------------------------------- /examples/bitrate_vs_ebn0.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | # -*- coding: utf-8 -*- 3 | 4 | from gnuradio import analog 5 | from gnuradio import blocks 6 | from gnuradio import digital 7 | from gnuradio import gr 8 | from gnuradio import trellis 9 | import lazyviterbi as lv 10 | 11 | import os 12 | import numpy 13 | import time 14 | import matplotlib.pyplot as plt 15 | 16 | 17 | class transmitter_channel_metrics(gr.top_block): 18 | def __init__(self, pkt_len, nb_pkt, EbN0dB, fsm): 19 | gr.top_block.__init__(self, "Transmitter, channel and metrics computation") 20 | 21 | ################################################## 22 | # Variables 23 | ################################################## 24 | self.pkt_len = pkt_len 25 | Rc=0.5 26 | self.const = const = digital.constellation_bpsk().base() 27 | 28 | var_c=1 29 | Nb=1 30 | Eb=var_c/(2.0*Nb*Rc) 31 | N0=Eb * 10**(-EbN0dB/10.0) 32 | noisevar=2*N0 33 | 34 | ################################################## 35 | # Blocks 36 | ################################################## 37 | self.bits_src = blocks.vector_source_b(numpy.random.randint(0, 2, nb_pkt*pkt_len), False) 38 | self.trellis_encoder = trellis.encoder_bb(trellis.fsm(fsm), 0, pkt_len) 39 | self.unpack = blocks.unpack_k_bits_bb(2) 40 | self.to_symbols = digital.chunks_to_symbols_bc((const.points()), 1) 41 | 42 | self.noise_src = analog.noise_source_c(analog.GR_GAUSSIAN, noisevar, 0) 43 | self.noise_adder = blocks.add_vcc(1) 44 | 45 | self.metrics_computer = trellis.metrics_c(4, 2, ([-1, -1, -1, 1, 1, -1, 1, 1]), digital.TRELLIS_EUCLIDEAN) 46 | 47 | self.dst = blocks.vector_sink_f() 48 | 49 | ################################################## 50 | # Connections 51 | ################################################## 52 | self.connect((self.bits_src, 0), (self.trellis_encoder, 0)) 53 | self.connect((self.trellis_encoder, 0), (self.unpack, 0)) 54 | self.connect((self.unpack, 0), (self.to_symbols, 0)) 55 | 56 | self.connect((self.to_symbols, 0), (self.noise_adder, 0)) 57 | self.connect((self.noise_src, 0), (self.noise_adder, 1)) 58 | self.connect((self.noise_adder, 0), (self.metrics_computer, 0)) 59 | 60 | self.connect((self.metrics_computer, 0), (self.dst, 0)) 61 | 62 | class ber_vs_ebn0_awgn(gr.top_block): 63 | 64 | def __init__(self, metrics, decoder): 65 | gr.top_block.__init__(self, "BER vs Eb/N0 (7,5) AWGN") 66 | 67 | ################################################## 68 | # Variables 69 | ################################################## 70 | self.metrics_source = blocks.vector_source_f(metrics, False) 71 | self.sink = blocks.null_sink(gr.sizeof_char) 72 | 73 | ################################################## 74 | # Connections 75 | ################################################## 76 | self.connect((self.metrics_source, 0), (decoder, 0)) 77 | self.connect((decoder, 0), (self.sink, 0)) 78 | 79 | def main(): 80 | #pkt_len = 8192 81 | pkt_len = 32768 82 | nb_pkt=100 83 | EbN0dB = numpy.linspace(0, 10, 11) 84 | bitrate_trellis_viterbi = numpy.zeros(len(EbN0dB)) 85 | bitrate_viterbi = numpy.zeros(len(EbN0dB)) 86 | bitrate_viterbi_vb = numpy.zeros(len(EbN0dB)) 87 | bitrate_viterbi_vs = numpy.zeros(len(EbN0dB)) 88 | bitrate_lazy = numpy.zeros(len(EbN0dB)) 89 | bitrate_dynamic = numpy.zeros(len(EbN0dB)) 90 | 91 | prefix = os.getcwd() 92 | #fsm = fsm = trellis.fsm(prefix + "/fsm/5_7.fsm") 93 | #fsm = fsm = trellis.fsm(prefix + "/fsm/229_159.fsm") 94 | #fsm = fsm = trellis.fsm(prefix + "/fsm/rsc_15_13.fsm") 95 | fsm = fsm = trellis.fsm(prefix + "/fsm/171_133.fsm") 96 | 97 | trellis_vit_dec = trellis.viterbi_b(trellis.fsm(fsm), pkt_len, 0, -1) 98 | vit_dec = lv.viterbi(trellis.fsm(fsm), pkt_len, 0, -1) 99 | vit_vb_dec = lv.viterbi_volk_branch(trellis.fsm(fsm), pkt_len, 0, -1) 100 | vit_vs_dec = lv.viterbi_volk_state(trellis.fsm(fsm), pkt_len, 0, -1) 101 | dyn_vit_dec = lv.dynamic_viterbi(trellis.fsm(fsm), pkt_len, 0, -1) 102 | lazy_dec = lv.lazy_viterbi(trellis.fsm(fsm), pkt_len, 0, -1) 103 | 104 | for i in range(0, len(EbN0dB)): 105 | print("Eb/N0=" + str(EbN0dB[i])) 106 | 107 | print("Simulating transmission") 108 | tb = transmitter_channel_metrics(pkt_len, nb_pkt, EbN0dB[i], fsm) 109 | tb.run() 110 | 111 | metrics=tb.dst.data() 112 | 113 | #Viterbi (gr-trellis) 114 | tb = ber_vs_ebn0_awgn(metrics, trellis_vit_dec) 115 | 116 | start_time=time.time() 117 | tb.run() 118 | elapsed_time=time.time() - start_time 119 | 120 | bitrate_trellis_viterbi[i] = pkt_len*nb_pkt/elapsed_time 121 | print("Bitrate Viterbi (gr-trellis):\t" + str(bitrate_trellis_viterbi[i])) 122 | 123 | #Viterbi (gr-lazyviterbi) 124 | tb = ber_vs_ebn0_awgn(metrics, vit_dec) 125 | 126 | start_time=time.time() 127 | tb.run() 128 | elapsed_time=time.time() - start_time 129 | 130 | bitrate_viterbi[i] = pkt_len*nb_pkt/elapsed_time 131 | print("Bitrate Viterbi (gr-lazyviterbi):\t" + str(bitrate_viterbi[i])) 132 | 133 | #Viterbi volk branch 134 | tb = ber_vs_ebn0_awgn(metrics, vit_vb_dec) 135 | 136 | start_time=time.time() 137 | tb.run() 138 | elapsed_time=time.time() - start_time 139 | 140 | bitrate_viterbi_vb[i] = pkt_len*nb_pkt/elapsed_time 141 | print("Bitrate Viterbi volk branch:\t" + str(bitrate_viterbi_vb[i])) 142 | 143 | #Viterbi volk state 144 | tb = ber_vs_ebn0_awgn(metrics, vit_vs_dec) 145 | 146 | start_time=time.time() 147 | tb.run() 148 | elapsed_time=time.time() - start_time 149 | 150 | bitrate_viterbi_vs[i] = pkt_len*nb_pkt/elapsed_time 151 | print("Bitrate Viterbi volk state:\t" + str(bitrate_viterbi_vs[i])) 152 | 153 | #Lazy Viterbi 154 | tb = ber_vs_ebn0_awgn(metrics, lazy_dec) 155 | 156 | start_time=time.time() 157 | tb.run() 158 | elapsed_time=time.time() - start_time 159 | 160 | bitrate_lazy[i] = pkt_len*nb_pkt/elapsed_time 161 | print("Bitrate Lazy:\t\t" + str(bitrate_lazy[i])) 162 | 163 | #Dynamic Viterbi 164 | tb = ber_vs_ebn0_awgn(metrics, dyn_vit_dec) 165 | 166 | start_time=time.time() 167 | tb.run() 168 | elapsed_time=time.time() - start_time 169 | 170 | bitrate_dynamic[i] = pkt_len*nb_pkt/elapsed_time 171 | print("Bitrate Dynamic:\t\t" + str(bitrate_dynamic[i])) 172 | 173 | print("") 174 | 175 | #Plot results 176 | plt.plot(EbN0dB, bitrate_trellis_viterbi, '-*', label="Viterbi (gr-trellis)") 177 | plt.plot(EbN0dB, bitrate_viterbi, '-+', label="Viterbi") 178 | plt.plot(EbN0dB, bitrate_viterbi_vb, '-+', label="Viterbi volk branch") 179 | plt.plot(EbN0dB, bitrate_viterbi_vs, '-d', label="Viterbi volk state") 180 | plt.plot(EbN0dB, bitrate_lazy, '-x', label="Lazy Viterbi") 181 | plt.plot(EbN0dB, bitrate_dynamic, '-o', label="Dynamique") 182 | 183 | plt.grid(which='both') 184 | plt.ylabel('Debit (bps)') 185 | plt.xlabel('Eb/N0 (dB)') 186 | plt.legend() 187 | plt.show() 188 | 189 | if __name__ == '__main__': 190 | main() 191 | 192 | -------------------------------------------------------------------------------- /examples/figures/i5_775_171_133_bitrate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexmrqt/gr-lazyviterbi/405999f89d3628f08a31340326dbe6f1df2a279e/examples/figures/i5_775_171_133_bitrate.png -------------------------------------------------------------------------------- /examples/figures/i5_775_229_159_bitrate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexmrqt/gr-lazyviterbi/405999f89d3628f08a31340326dbe6f1df2a279e/examples/figures/i5_775_229_159_bitrate.png -------------------------------------------------------------------------------- /examples/figures/i5_775_5_7_bitrate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexmrqt/gr-lazyviterbi/405999f89d3628f08a31340326dbe6f1df2a279e/examples/figures/i5_775_5_7_bitrate.png -------------------------------------------------------------------------------- /examples/figures/i5_775_rsc_15_13_bitrate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexmrqt/gr-lazyviterbi/405999f89d3628f08a31340326dbe6f1df2a279e/examples/figures/i5_775_rsc_15_13_bitrate.png -------------------------------------------------------------------------------- /examples/fsm/171_133.fsm: -------------------------------------------------------------------------------- 1 | 2 64 4 2 | 3 | 4 | 0 32 5 | 0 32 6 | 1 33 7 | 1 33 8 | 2 34 9 | 2 34 10 | 3 35 11 | 3 35 12 | 4 36 13 | 4 36 14 | 5 37 15 | 5 37 16 | 6 38 17 | 6 38 18 | 7 39 19 | 7 39 20 | 8 40 21 | 8 40 22 | 9 41 23 | 9 41 24 | 10 42 25 | 10 42 26 | 11 43 27 | 11 43 28 | 12 44 29 | 12 44 30 | 13 45 31 | 13 45 32 | 14 46 33 | 14 46 34 | 15 47 35 | 15 47 36 | 16 48 37 | 16 48 38 | 17 49 39 | 17 49 40 | 18 50 41 | 18 50 42 | 19 51 43 | 19 51 44 | 20 52 45 | 20 52 46 | 21 53 47 | 21 53 48 | 22 54 49 | 22 54 50 | 23 55 51 | 23 55 52 | 24 56 53 | 24 56 54 | 25 57 55 | 25 57 56 | 26 58 57 | 26 58 58 | 27 59 59 | 27 59 60 | 28 60 61 | 28 60 62 | 29 61 63 | 29 61 64 | 30 62 65 | 30 62 66 | 31 63 67 | 31 63 68 | 69 | 0 3 70 | 3 0 71 | 1 2 72 | 2 1 73 | 0 3 74 | 3 0 75 | 1 2 76 | 2 1 77 | 3 0 78 | 0 3 79 | 2 1 80 | 1 2 81 | 3 0 82 | 0 3 83 | 2 1 84 | 1 2 85 | 3 0 86 | 0 3 87 | 2 1 88 | 1 2 89 | 3 0 90 | 0 3 91 | 2 1 92 | 1 2 93 | 0 3 94 | 3 0 95 | 1 2 96 | 2 1 97 | 0 3 98 | 3 0 99 | 1 2 100 | 2 1 101 | 2 1 102 | 1 2 103 | 3 0 104 | 0 3 105 | 2 1 106 | 1 2 107 | 3 0 108 | 0 3 109 | 1 2 110 | 2 1 111 | 0 3 112 | 3 0 113 | 1 2 114 | 2 1 115 | 0 3 116 | 3 0 117 | 1 2 118 | 2 1 119 | 0 3 120 | 3 0 121 | 1 2 122 | 2 1 123 | 0 3 124 | 3 0 125 | 2 1 126 | 1 2 127 | 3 0 128 | 0 3 129 | 2 1 130 | 1 2 131 | 3 0 132 | 0 3 133 | 134 | DVB-T convolutional code (171, 133) 135 | -------------------------------------------------------------------------------- /examples/fsm/229_159.fsm: -------------------------------------------------------------------------------- 1 | 2 128 4 2 | 3 | 0 64 4 | 0 64 5 | 1 65 6 | 1 65 7 | 2 66 8 | 2 66 9 | 3 67 10 | 3 67 11 | 4 68 12 | 4 68 13 | 5 69 14 | 5 69 15 | 6 70 16 | 6 70 17 | 7 71 18 | 7 71 19 | 8 72 20 | 8 72 21 | 9 73 22 | 9 73 23 | 10 74 24 | 10 74 25 | 11 75 26 | 11 75 27 | 12 76 28 | 12 76 29 | 13 77 30 | 13 77 31 | 14 78 32 | 14 78 33 | 15 79 34 | 15 79 35 | 16 80 36 | 16 80 37 | 17 81 38 | 17 81 39 | 18 82 40 | 18 82 41 | 19 83 42 | 19 83 43 | 20 84 44 | 20 84 45 | 21 85 46 | 21 85 47 | 22 86 48 | 22 86 49 | 23 87 50 | 23 87 51 | 24 88 52 | 24 88 53 | 25 89 54 | 25 89 55 | 26 90 56 | 26 90 57 | 27 91 58 | 27 91 59 | 28 92 60 | 28 92 61 | 29 93 62 | 29 93 63 | 30 94 64 | 30 94 65 | 31 95 66 | 31 95 67 | 32 96 68 | 32 96 69 | 33 97 70 | 33 97 71 | 34 98 72 | 34 98 73 | 35 99 74 | 35 99 75 | 36 100 76 | 36 100 77 | 37 101 78 | 37 101 79 | 38 102 80 | 38 102 81 | 39 103 82 | 39 103 83 | 40 104 84 | 40 104 85 | 41 105 86 | 41 105 87 | 42 106 88 | 42 106 89 | 43 107 90 | 43 107 91 | 44 108 92 | 44 108 93 | 45 109 94 | 45 109 95 | 46 110 96 | 46 110 97 | 47 111 98 | 47 111 99 | 48 112 100 | 48 112 101 | 49 113 102 | 49 113 103 | 50 114 104 | 50 114 105 | 51 115 106 | 51 115 107 | 52 116 108 | 52 116 109 | 53 117 110 | 53 117 111 | 54 118 112 | 54 118 113 | 55 119 114 | 55 119 115 | 56 120 116 | 56 120 117 | 57 121 118 | 57 121 119 | 58 122 120 | 58 122 121 | 59 123 122 | 59 123 123 | 60 124 124 | 60 124 125 | 61 125 126 | 61 125 127 | 62 126 128 | 62 126 129 | 63 127 130 | 63 127 131 | 132 | 0 3 133 | 3 0 134 | 1 2 135 | 2 1 136 | 3 0 137 | 0 3 138 | 2 1 139 | 1 2 140 | 1 2 141 | 2 1 142 | 0 3 143 | 3 0 144 | 2 1 145 | 1 2 146 | 3 0 147 | 0 3 148 | 1 2 149 | 2 1 150 | 0 3 151 | 3 0 152 | 2 1 153 | 1 2 154 | 3 0 155 | 0 3 156 | 0 3 157 | 3 0 158 | 1 2 159 | 2 1 160 | 3 0 161 | 0 3 162 | 2 1 163 | 1 2 164 | 2 1 165 | 1 2 166 | 3 0 167 | 0 3 168 | 1 2 169 | 2 1 170 | 0 3 171 | 3 0 172 | 3 0 173 | 0 3 174 | 2 1 175 | 1 2 176 | 0 3 177 | 3 0 178 | 1 2 179 | 2 1 180 | 3 0 181 | 0 3 182 | 2 1 183 | 1 2 184 | 0 3 185 | 3 0 186 | 1 2 187 | 2 1 188 | 2 1 189 | 1 2 190 | 3 0 191 | 0 3 192 | 1 2 193 | 2 1 194 | 0 3 195 | 3 0 196 | 2 1 197 | 1 2 198 | 3 0 199 | 0 3 200 | 1 2 201 | 2 1 202 | 0 3 203 | 3 0 204 | 3 0 205 | 0 3 206 | 2 1 207 | 1 2 208 | 0 3 209 | 3 0 210 | 1 2 211 | 2 1 212 | 3 0 213 | 0 3 214 | 2 1 215 | 1 2 216 | 0 3 217 | 3 0 218 | 1 2 219 | 2 1 220 | 2 1 221 | 1 2 222 | 3 0 223 | 0 3 224 | 1 2 225 | 2 1 226 | 0 3 227 | 3 0 228 | 0 3 229 | 3 0 230 | 1 2 231 | 2 1 232 | 3 0 233 | 0 3 234 | 2 1 235 | 1 2 236 | 1 2 237 | 2 1 238 | 0 3 239 | 3 0 240 | 2 1 241 | 1 2 242 | 3 0 243 | 0 3 244 | 1 2 245 | 2 1 246 | 0 3 247 | 3 0 248 | 2 1 249 | 1 2 250 | 3 0 251 | 0 3 252 | 0 3 253 | 3 0 254 | 1 2 255 | 2 1 256 | 3 0 257 | 0 3 258 | 2 1 259 | 1 2 260 | 261 | 262 | 263 | GM1o2_128=[1+D+D^2+D^5+D^7 1+D^3+D^4+D^5+D^6+D^7] 264 | =[11100101 10011111] 265 | =[229 159] 266 | -------------------------------------------------------------------------------- /examples/fsm/5_7.fsm: -------------------------------------------------------------------------------- 1 | 2 4 4 2 | 3 | 0 2 4 | 0 2 5 | 1 3 6 | 1 3 7 | 8 | 0 3 9 | 3 0 10 | 1 2 11 | 2 1 12 | 13 | AWGN CC from Proakis-Salehi pg 779 14 | GM1o2_4=[1+D^2, 1+D+D^2] = [5, 7] (in decimal); 15 | -------------------------------------------------------------------------------- /examples/fsm/rsc_15_13.fsm: -------------------------------------------------------------------------------- 1 | 2 8 4 2 | 3 | 0 4 4 | 4 0 5 | 5 1 6 | 1 5 7 | 2 6 8 | 6 2 9 | 7 3 10 | 3 7 11 | 12 | 0 3 13 | 0 3 14 | 1 2 15 | 1 2 16 | 1 2 17 | 1 2 18 | 0 3 19 | 0 3 20 | -------------------------------------------------------------------------------- /grc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-lazyviterbi 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | install(FILES 21 | lazyviterbi_viterbi.block.yml 22 | lazyviterbi_lazy_viterbi.block.yml 23 | lazyviterbi_dynamic_viterbi.block.yml 24 | lazyviterbi_viterbi_volk_branch.block.yml 25 | lazyviterbi_viterbi_volk_state.block.yml DESTINATION share/gnuradio/grc/blocks 26 | ) 27 | -------------------------------------------------------------------------------- /grc/lazyviterbi_dynamic_viterbi.block.yml: -------------------------------------------------------------------------------- 1 | id: lazyviterbi_dynamic_viterbi 2 | label: Dynamic Viterbi 3 | category: '[lazyviterbi]' 4 | 5 | templates: 6 | imports: |- 7 | import lazyviterbi 8 | from gnuradio import trellis 9 | make: lazyviterbi.dynamic_viterbi(trellis.fsm(${fsm_args}), ${block_size}, ${init_state}, ${final_state}, ${thres}) 10 | 11 | parameters: 12 | - id: fsm_args 13 | label: FSM Args 14 | dtype: raw 15 | - id: block_size 16 | label: Block Size 17 | dtype: int 18 | - id: init_state 19 | label: Initial State 20 | default: 0 21 | dtype: int 22 | - id: final_state 23 | label: Final State 24 | default: -1 25 | dtype: int 26 | - id: thres 27 | label: Threshold 28 | default: 15.0 29 | dtype: float 30 | 31 | # Make one 'inputs' list entry per input and one 'outputs' list entry per output. 32 | # Keys include: 33 | # * label (an identifier for the GUI) 34 | # * domain (optional - stream or message. Default is stream) 35 | # * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) 36 | # * vlen (optional - data stream vector length. Default is 1) 37 | # * optional (optional - set to 1 for optional inputs. Default is 0) 38 | inputs: 39 | - label: in 40 | domain: stream 41 | dtype: float 42 | 43 | outputs: 44 | - label: in 45 | domain: stream 46 | dtype: byte 47 | 48 | documentation: |- 49 | Dynamic Viterbi Decoder. \ 50 | The fsm arguments are passed directly to the trellis.fsm() constructor. \ 51 | Block size is the length of the sequence taken into account for decoding. \ 52 | Initial state must contain the initial state of the encoder (-1 if unknown). \ 53 | Final state must contain the final state of the encoder (-1 if unknown). \ 54 | Thres is the ratio between the mean of max. branch metrics and mean of min. 55 | branch metrics. If this ratio is > thres, then this block uses the Lazy Viterbi 56 | algorithm, otherwise it uses the classical Viterbi algorithm. 57 | 58 | # 'file_format' specifies the version of the GRC yml format used in the file 59 | # and should usually not be changed. 60 | file_format: 1 61 | -------------------------------------------------------------------------------- /grc/lazyviterbi_lazy_viterbi.block.yml: -------------------------------------------------------------------------------- 1 | id: lazyviterbi_lazy_viterbi 2 | label: Lazy Viterbi 3 | category: '[lazyviterbi]' 4 | 5 | templates: 6 | imports: |- 7 | import lazyviterbi 8 | from gnuradio import trellis 9 | make: lazyviterbi.lazy_viterbi(trellis.fsm(${fsm_args}), ${block_size}, ${init_state}, ${final_state}) 10 | 11 | parameters: 12 | - id: fsm_args 13 | label: FSM Args 14 | dtype: raw 15 | - id: block_size 16 | label: Block Size 17 | dtype: int 18 | - id: init_state 19 | label: Initial State 20 | default: 0 21 | dtype: int 22 | - id: final_state 23 | label: Final State 24 | default: -1 25 | dtype: int 26 | 27 | # Make one 'inputs' list entry per input and one 'outputs' list entry per output. 28 | # Keys include: 29 | # * label (an identifier for the GUI) 30 | # * domain (optional - stream or message. Default is stream) 31 | # * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) 32 | # * vlen (optional - data stream vector length. Default is 1) 33 | # * optional (optional - set to 1 for optional inputs. Default is 0) 34 | inputs: 35 | - label: in 36 | domain: stream 37 | dtype: float 38 | 39 | outputs: 40 | - label: in 41 | domain: stream 42 | dtype: byte 43 | 44 | documentation: |- 45 | Lazy Viterbi Decoder. \ 46 | The fsm arguments are passed directly to the trellis.fsm() constructor. \ 47 | Block size is the length of the sequence taken into account for decoding. \ 48 | Initial state must contain the initial state of the encoder (-1 if unknown). \ 49 | Final state must contain the final state of the encoder (-1 if unknown). 50 | 51 | # 'file_format' specifies the version of the GRC yml format used in the file 52 | # and should usually not be changed. 53 | file_format: 1 54 | -------------------------------------------------------------------------------- /grc/lazyviterbi_viterbi.block.yml: -------------------------------------------------------------------------------- 1 | id: lazyviterbi_viterbi 2 | label: Viterbi 3 | category: '[lazyviterbi]' 4 | 5 | templates: 6 | imports: |- 7 | import lazyviterbi 8 | from gnuradio import trellis 9 | make: lazyviterbi.viterbi(trellis.fsm(${fsm_args}), ${block_size}, ${init_state}, ${final_state}) 10 | 11 | parameters: 12 | - id: fsm_args 13 | label: FSM Args 14 | dtype: raw 15 | - id: block_size 16 | label: Block Size 17 | dtype: int 18 | - id: init_state 19 | label: Initial State 20 | default: 0 21 | dtype: int 22 | - id: final_state 23 | label: Final State 24 | default: -1 25 | dtype: int 26 | 27 | # Make one 'inputs' list entry per input and one 'outputs' list entry per output. 28 | # Keys include: 29 | # * label (an identifier for the GUI) 30 | # * domain (optional - stream or message. Default is stream) 31 | # * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) 32 | # * vlen (optional - data stream vector length. Default is 1) 33 | # * optional (optional - set to 1 for optional inputs. Default is 0) 34 | inputs: 35 | - label: in 36 | domain: stream 37 | dtype: float 38 | 39 | outputs: 40 | - label: in 41 | domain: stream 42 | dtype: byte 43 | 44 | documentation: |- 45 | Viterbi Decoder. \ 46 | The fsm arguments are passed directly to the trellis.fsm() constructor. \ 47 | Block size is the length of the sequence taken into account for decoding. \ 48 | Initial state must contain the initial state of the encoder (-1 if unknown). \ 49 | Final state must contain the final state of the encoder (-1 if unknown). 50 | 51 | # 'file_format' specifies the version of the GRC yml format used in the file 52 | # and should usually not be changed. 53 | file_format: 1 54 | -------------------------------------------------------------------------------- /grc/lazyviterbi_viterbi_volk_branch.block.yml: -------------------------------------------------------------------------------- 1 | id: lazyviterbi_viterbi_volk_branch 2 | label: Viterbi Volk Branch 3 | category: '[lazyviterbi]' 4 | 5 | templates: 6 | imports: |- 7 | import lazyviterbi 8 | from gnuradio import trellis 9 | make: lazyviterbi.viterbi_volk_branch(trellis.fsm(${fsm_args}), ${block_size}, ${init_state}, ${final_state}) 10 | 11 | parameters: 12 | - id: fsm_args 13 | label: FSM Args 14 | dtype: raw 15 | - id: block_size 16 | label: Block Size 17 | dtype: int 18 | - id: init_state 19 | label: Initial State 20 | default: 0 21 | dtype: int 22 | - id: final_state 23 | label: Final State 24 | default: -1 25 | dtype: int 26 | 27 | # Make one 'inputs' list entry per input and one 'outputs' list entry per output. 28 | # Keys include: 29 | # * label (an identifier for the GUI) 30 | # * domain (optional - stream or message. Default is stream) 31 | # * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) 32 | # * vlen (optional - data stream vector length. Default is 1) 33 | # * optional (optional - set to 1 for optional inputs. Default is 0) 34 | inputs: 35 | - label: in 36 | domain: stream 37 | dtype: float 38 | 39 | outputs: 40 | - label: in 41 | domain: stream 42 | dtype: byte 43 | 44 | documentation: |- 45 | Viterbi Decoder with Volk optimization for parallel processing of branches. \ 46 | In this implementation, for each state s, Add-Compare-Select is performed in 47 | parallell for each branch leading to s.\ 48 | Use this when the number of branch leading to states is larger that the number 49 | of states. \ 50 | The fsm arguments are passed directly to the trellis.fsm() constructor. \ 51 | Block size is the length of the sequence taken into account for decoding. \ 52 | Initial state must contain the initial state of the encoder (-1 if unknown). \ 53 | Final state must contain the final state of the encoder (-1 if unknown). 54 | 55 | # 'file_format' specifies the version of the GRC yml format used in the file 56 | # and should usually not be changed. 57 | file_format: 1 58 | -------------------------------------------------------------------------------- /grc/lazyviterbi_viterbi_volk_state.block.yml: -------------------------------------------------------------------------------- 1 | id: lazyviterbi_viterbi_volk_state 2 | label: viterbi_volk_state 3 | category: '[lazyviterbi]' 4 | 5 | templates: 6 | imports: |- 7 | import lazyviterbi 8 | from gnuradio import trellis 9 | make: lazyviterbi.viterbi_volk_state(trellis.fsm(${fsm_args}), ${block_size}, ${init_state}, ${final_state}) 10 | 11 | parameters: 12 | - id: fsm_args 13 | label: FSM Args 14 | dtype: raw 15 | - id: block_size 16 | label: Block Size 17 | dtype: int 18 | - id: init_state 19 | label: Initial State 20 | default: 0 21 | dtype: int 22 | - id: final_state 23 | label: Final State 24 | default: -1 25 | dtype: int 26 | 27 | # Make one 'inputs' list entry per input and one 'outputs' list entry per output. 28 | # Keys include: 29 | # * label (an identifier for the GUI) 30 | # * domain (optional - stream or message. Default is stream) 31 | # * dtype (e.g. int, float, complex, byte, short, xxx_vector, ...) 32 | # * vlen (optional - data stream vector length. Default is 1) 33 | # * optional (optional - set to 1 for optional inputs. Default is 0) 34 | inputs: 35 | - label: in 36 | domain: stream 37 | dtype: float 38 | 39 | outputs: 40 | - label: in 41 | domain: stream 42 | dtype: byte 43 | 44 | documentation: |- 45 | Viterbi Decoder with Volk optimization for parallel processing of branches. \ 46 | Use this when the number of state is larger that the number 47 | of branch leading to states. \ 48 | The fsm arguments are passed directly to the trellis.fsm() constructor. \ 49 | Block size is the length of the sequence taken into account for decoding. \ 50 | Initial state must contain the initial state of the encoder (-1 if unknown). \ 51 | Final state must contain the final state of the encoder (-1 if unknown). 52 | 53 | # 'file_format' specifies the version of the GRC yml format used in the file 54 | # and should usually not be changed. 55 | file_format: 1 56 | -------------------------------------------------------------------------------- /include/lazyviterbi/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011,2012 Free Software Foundation, Inc. 2 | # 3 | # This file is part of GNU Radio 4 | # 5 | # GNU Radio is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 3, or (at your option) 8 | # any later version. 9 | # 10 | # GNU Radio is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License 16 | # along with GNU Radio; see the file COPYING. If not, write to 17 | # the Free Software Foundation, Inc., 51 Franklin Street, 18 | # Boston, MA 02110-1301, USA. 19 | 20 | ######################################################################## 21 | # Install public header files 22 | ######################################################################## 23 | install(FILES 24 | api.h 25 | lazy_viterbi.h 26 | dynamic_viterbi.h 27 | viterbi.h 28 | viterbi_volk_branch.h 29 | viterbi_volk_state.h DESTINATION include/lazyviterbi 30 | ) 31 | -------------------------------------------------------------------------------- /include/lazyviterbi/api.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * GNU Radio is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 3, or (at your option) 9 | * any later version. 10 | * 11 | * GNU Radio is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with GNU Radio; see the file COPYING. If not, write to 18 | * the Free Software Foundation, Inc., 51 Franklin Street, 19 | * Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #ifndef INCLUDED_LAZYVITERBI_API_H 23 | #define INCLUDED_LAZYVITERBI_API_H 24 | 25 | #include 26 | 27 | #ifdef gnuradio_lazyviterbi_EXPORTS 28 | # define LAZYVITERBI_API __GR_ATTR_EXPORT 29 | #else 30 | # define LAZYVITERBI_API __GR_ATTR_IMPORT 31 | #endif 32 | 33 | #endif /* INCLUDED_LAZYVITERBI_API_H */ 34 | -------------------------------------------------------------------------------- /include/lazyviterbi/dynamic_viterbi.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2017 <+YOU OR YOUR COMPANY+>. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | 22 | #ifndef INCLUDED_LAZYVITERBI_DYNAMIC_VITERBI_H 23 | #define INCLUDED_LAZYVITERBI_DYNAMIC_VITERBI_H 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace gr { 30 | namespace lazyviterbi { 31 | 32 | /*! 33 | * \brief Switch between the Viterbi and the Lazy Viterbi algorithm depending 34 | * on channel conditions. 35 | * 36 | * The decision wether to choose between the two is based on the ratio of 37 | * the mean of maximum branch metrics and minimum branch metrics: 38 | * \f[ 39 | * Q = \frac{\sum_{k=0}^{K-1} \max_{o\in [0 : O-1]}\{\text{metrics}_k[o]\}} 40 | * {\sum_{k=0}^{K-1} \min_{o\in [0 : O-1]}\{\text{metrics}_k[o]\}}, 41 | * \f] 42 | * where: 43 | * - \f$ K \f$ is the length of the data block; 44 | * - \f$ O \f$ is the number of possible output symbols of the FSM under 45 | * consideration; 46 | * - \f$ \text{metrics}_k[o] \f$ is the branch metric at time index 47 | * \f$ k \f$ for output symbol \f$ o \f$. 48 | * 49 | * Then, if \f$ Q > \text{threshold} \f$, then the Lazy Viterbi is chosen, 50 | * otherwise the classical Viterbi algorithm is chosen. 51 | * 52 | */ 53 | class LAZYVITERBI_API dynamic_viterbi : virtual public gr::block 54 | { 55 | public: 56 | typedef boost::shared_ptr sptr; 57 | 58 | /*! 59 | * \brief Return a shared_ptr to a new instance of lazyviterbi::dynamic_viterbi. 60 | * 61 | * To avoid accidental use of raw pointers, lazyviterbi::dynamic_viterbi's 62 | * constructor is in a private implementation 63 | * class. lazyviterbi::dynamic_viterbi::make is the public interface for 64 | * creating new instances. 65 | * 66 | * \param FSM Trellis of the code. 67 | * \param K Length of a block of data. 68 | * \param S0 Initial state of the encoder (set to -1 if unknown). 69 | * \param SK Final state of the encoder (set to -1 if unknown). 70 | * \param thres Threshold for choosing the Lazy Viterbi algorithm over the 71 | * classical Viterbi algorithm. 72 | */ 73 | static sptr make(const gr::trellis::fsm &FSM, int K, int S0, int SK, float thres=15.0); 74 | 75 | /*! 76 | * \return The trellis used by the decoder. 77 | */ 78 | virtual gr::trellis::fsm FSM() const = 0; 79 | /*! 80 | * \return The data blocks length considered by the decoder. 81 | */ 82 | virtual int K() const = 0; 83 | /*! 84 | * \return The initial state of the encoder (as given to the decoder, -1 85 | * if unspecified). 86 | */ 87 | virtual int S0() const = 0; 88 | /*! 89 | * \return The final state of the encoder (as given to the decoder, -1 if 90 | * unspecified). 91 | */ 92 | virtual int SK() const = 0; 93 | /*! 94 | * \return The threshold use to choose the algorithm. 95 | */ 96 | virtual float thres() const = 0; 97 | /*! 98 | * \return True if the Lazy Viterbi algorithm is currently used. 99 | */ 100 | virtual bool is_lazy() const = 0; 101 | 102 | /*! 103 | * Gives the initial state of the encoder to the decoder (set to -1 if unknown). 104 | */ 105 | virtual void set_S0(int S0) = 0; 106 | /*! 107 | * Gives the final state of the encoder to the decoder (set to -1 if unknown). 108 | */ 109 | virtual void set_SK(int SK) = 0; 110 | /*! 111 | * Set the threshold value. 112 | */ 113 | virtual void set_thres(float thres) = 0; 114 | }; 115 | 116 | } // namespace lazyviterbi 117 | } // namespace gr 118 | 119 | #endif /* INCLUDED_LAZYVITERBI_DYNAMIC_VITERBI_H */ 120 | 121 | -------------------------------------------------------------------------------- /include/lazyviterbi/lazy_viterbi.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2017 Free Software Foundation, Inc. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | 22 | #ifndef INCLUDED_LAZYVITERBI_LAZY_VITERBI_H 23 | #define INCLUDED_LAZYVITERBI_LAZY_VITERBI_H 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | namespace gr { 30 | namespace lazyviterbi { 31 | 32 | /*! 33 | * \brief A maximum likelihood decoder. 34 | * 35 | * This block implements the Viterbi algorithm for decoding or equalization 36 | * in the way described in \cite Feldman2002. 37 | * 38 | * It takes euclidean metrics as an input and produces decoded sequences. 39 | * 40 | * The idea is to see the Viterbi algorithm as an instance of a shortest path 41 | * algorithm for trellis. While the original Viterbi algorithm goes through 42 | * every path of the trellis to calculate the shortest path \cite Forney1973, 43 | * the Lazy Viterbi algorithm re-uses concepts from Dijkstra's algorithm to 44 | * speed-up shortest path calculation in the moderate and high SNR regions. 45 | * 46 | * This implementation provides a significant speedup at moderate SNRs, 47 | * but is slower at low SNR. 48 | * Finally, it shows slightly worse performance than gr-trellis's Viterbi 49 | * algorithm as it converts the metrics from float to 8-bit integers. 50 | */ 51 | class LAZYVITERBI_API lazy_viterbi : virtual public gr::block 52 | { 53 | public: 54 | typedef boost::shared_ptr sptr; 55 | 56 | /*! 57 | * \brief Return a shared_ptr to a new instance of lazyviterbi::lazy_viterbi. 58 | * 59 | * To avoid accidental use of raw pointers, lazyviterbi::lazy_viterbi's 60 | * constructor is in a private implementation 61 | * class. lazyviterbi::lazy_viterbi::make is the public interface for 62 | * creating new instances. 63 | * 64 | * \param FSM Trellis of the code. 65 | * \param K Length of a block of data. 66 | * \param S0 Initial state of the encoder (set to -1 if unknown). 67 | * \param SK Final state of the encoder (set to -1 if unknown). 68 | */ 69 | static sptr make(const gr::trellis::fsm &FSM, int K, int S0, int SK); 70 | 71 | /*! 72 | * \return The trellis used by the decoder. 73 | */ 74 | virtual gr::trellis::fsm FSM() const = 0; 75 | /*! 76 | * \return The data blocks length considered by the decoder. 77 | */ 78 | virtual int K() const = 0; 79 | /*! 80 | * \return The initial state of the encoder (as given to the decoder, -1 81 | * if unspecified). 82 | */ 83 | virtual int S0() const = 0; 84 | /*! 85 | * \return The final state of the encoder (as given to the decoder, -1 if 86 | * unspecified). 87 | */ 88 | virtual int SK() const = 0; 89 | 90 | /*! 91 | * Gives the initial state of the encoder to the decoder (set to -1 if unknown). 92 | */ 93 | virtual void set_S0(int S0) = 0; 94 | /*! 95 | * Gives the final state of the encoder to the decoder (set to -1 if unknown). 96 | */ 97 | virtual void set_SK(int SK) = 0; 98 | 99 | /*! 100 | * \brief Process the input metrics. 101 | * 102 | * In order to avoid the algorithm for exploring more paths than necessary 103 | * due to sporadic noise impulse (which affects equally every branches at 104 | * a given time index), each branch metrics at each time index are normalized 105 | * so that the lowest metric is 0. 106 | * This writes : 107 | * \f{equation}{ 108 | * \text{metrics}[k.O + j] = \text{in}[k.O + j] - 109 | * \min_{i\in [0:O-1]} \{ \text{metrics}[k.O + i] \}. 110 | * \f} 111 | * whith \f$ k \f$ the time index, \f$ O \f$ the number of output symbols and \f$ i \in [0:O-1] \f$. 112 | * 113 | * \param *in Input branch metrics. 114 | * \param *metrics Processed branch metrics. 115 | * \param K Length of a block of data. 116 | * \param O number of possible output symbols of the FSM under consideration. 117 | */ 118 | virtual void lazy_viteri_metrics_norm(const float *in, uint8_t* metrics, 119 | int K, int O) = 0; 120 | 121 | /*! 122 | * \brief Actual Lazy Viterbi algorithm implementation 123 | * 124 | * \param I The number of input sequences (e.g. 2 for binary codes). 125 | * \param S The number of states in the trellis. 126 | * \param O The number of output sequences (e.g. 4 for a binary code with a coding efficiency of 1/2). 127 | * \param NS Gives the next state ns of a branch defined by its initial state s 128 | * and its input symbol i : NS[s*I+i]=ns. 129 | * \param OS Gives the output symbol os of a branch defined by its initial state s 130 | * and its input symbol i : OS[s*I+i]=os. 131 | * \param K Length of a block of data. 132 | * \param S0 Initial state of the encoder (set to -1 if unknown). 133 | * \param SK Final state of the encoder (set to -1 if unknown). 134 | * \param in Input euclidean metrics for the algorithm. 135 | * \param out Output decoded sequence. 136 | * 137 | */ 138 | virtual void lazy_viterbi_algorithm(int I, int S, int O, 139 | const std::vector &NS, const std::vector &OS, int K, int S0, 140 | int SK, const float *in, unsigned char *out) = 0; 141 | 142 | }; 143 | 144 | } // namespace lazyviterbi 145 | } // namespace gr 146 | 147 | #endif /* INCLUDED_LAZYVITERBI_LAZY_VITERBI_H */ 148 | 149 | -------------------------------------------------------------------------------- /include/lazyviterbi/viterbi.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2018 Free Software Foundation, Inc. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | 22 | #ifndef INCLUDED_LAZYVITERBI_VITERBI_H 23 | #define INCLUDED_LAZYVITERBI_VITERBI_H 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | namespace gr { 31 | namespace lazyviterbi { 32 | 33 | /*! 34 | * \brief A maximum likelihood decoder. 35 | * 36 | * This block implements the Viterbi algorithm in its classical form, 37 | * as way described e.g., in \cite Forney1973. 38 | * 39 | * It takes euclidean metrics as an input and produces decoded sequences. 40 | */ 41 | class LAZYVITERBI_API viterbi : virtual public gr::block 42 | { 43 | public: 44 | typedef boost::shared_ptr sptr; 45 | 46 | /*! 47 | * \brief Return a shared_ptr to a new instance of lazyviterbi::viterbi. 48 | * 49 | * To avoid accidental use of raw pointers, lazyviterbi::viterbi's 50 | * constructor is in a private implementation 51 | * class. lazyviterbi::viterbi::make is the public interface for 52 | * creating new instances. 53 | * 54 | * \param FSM Trellis of the code. 55 | * \param K Length of a block of data. 56 | * \param S0 Initial state of the encoder (set to -1 if unknown). 57 | * \param SK Final state of the encoder (set to -1 if unknown). 58 | */ 59 | static sptr make(const gr::trellis::fsm &FSM, int K, int S0, int SK); 60 | 61 | /*! 62 | * \return The trellis used by the decoder. 63 | */ 64 | virtual gr::trellis::fsm FSM() const = 0; 65 | /*! 66 | * \return The data blocks length considered by the decoder. 67 | */ 68 | virtual int K() const = 0; 69 | /*! 70 | * \return The initial state of the encoder (as given by the decoder, -1 71 | * if unspecified). 72 | */ 73 | virtual int S0() const = 0; 74 | /*! 75 | * \return The final state of the encoder (as given by the decoder, -1 if 76 | * unspecified). 77 | */ 78 | virtual int SK() const = 0; 79 | 80 | /*! 81 | * Gives the initial state of the encoder to the decoder (set to -1 if unknown). 82 | */ 83 | virtual void set_S0(int S0) = 0; 84 | /*! 85 | * Gives the final state of the encoder to the decoder (set to -1 if unknown). 86 | */ 87 | virtual void set_SK(int SK) = 0; 88 | 89 | /*! 90 | * \brief Actual Viterbi algorithm implementation 91 | * 92 | * \param I The number of input sequences (e.g. 2 for binary codes). 93 | * \param S The number of states in the trellis. 94 | * \param O The number of output sequences (e.g. 4 for a binary code with a coding efficiency of 1/2). 95 | * \param NS Gives the next state ns of a branch defined by its initial state s 96 | * and its input symbol i : NS[s*I+i]=ns. 97 | * \param OS Gives the output symbol os of a branch defined by its initial state s 98 | * and its input symbol i : OS[s*I+i]=os. 99 | * \param PS Such that PS[s] contains all the previous states having a branch with state s. 100 | * \param PI Such that PI[s] contains all the inputs yielding to state s. 101 | * \param K Length of a block of data. 102 | * \param S0 Initial state of the encoder (set to -1 if unknown). 103 | * \param SK Final state of the encoder (set to -1 if unknown). 104 | * \param in Input euclidean metrics for the algorithm. 105 | * \param out Output decoded sequence. 106 | * 107 | */ 108 | virtual void viterbi_algorithm(int I, int S, int O, 109 | const std::vector &NS, const std::vector &OS, 110 | const std::vector< std::vector > &PS, 111 | const std::vector< std::vector > &PI, int K, int S0, int SK, 112 | const float *in, unsigned char *out) = 0; 113 | }; 114 | 115 | } // namespace lazyviterbi 116 | } // namespace gr 117 | 118 | #endif /* INCLUDED_LAZYVITERBI_VITERBI_H */ 119 | 120 | -------------------------------------------------------------------------------- /include/lazyviterbi/viterbi_volk_branch.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2019 Alexandre Marquet. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef INCLUDED_LAZYVITERBI_VITERBI_VOLK_BRANCH_H 22 | #define INCLUDED_LAZYVITERBI_VITERBI_VOLK_BRANCH_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace gr { 30 | namespace lazyviterbi { 31 | 32 | /*! 33 | * \brief A maximum likelihood decoder. 34 | * 35 | * This block implements the Viterbi algorithm in its classical form, 36 | * as way described e.g., in \cite Forney1973. 37 | * It uses Volk to parallelize Add-Compare-Select operations, however, 38 | * each state is treated sequentially. 39 | * 40 | * It can bring significant speedup for trellis where the number of branches 41 | * yielding to states is larger than the number of states. 42 | * 43 | * It takes euclidean metrics as an input and produces decoded sequences. 44 | */ 45 | class LAZYVITERBI_API viterbi_volk_branch : virtual public gr::block 46 | { 47 | public: 48 | typedef boost::shared_ptr sptr; 49 | 50 | /*! 51 | * \brief Return a shared_ptr to a new instance of lazyviterbi::viterbi_volk_branch. 52 | * 53 | * To avoid accidental use of raw pointers, lazyviterbi::viterbi_volk_branch's 54 | * constructor is in a private implementation 55 | * class. lazyviterbi::viterbi_volk_branch::make is the public interface for 56 | * creating new instances. 57 | * 58 | * \param FSM Trellis of the code. 59 | * \param K Length of a block of data. 60 | * \param S0 Initial state of the encoder (set to -1 if unknown). 61 | * \param SK Final state of the encoder (set to -1 if unknown). 62 | */ 63 | static sptr make(const gr::trellis::fsm &FSM, int K, int S0, int SK); 64 | 65 | /*! 66 | * \return The trellis used by the decoder. 67 | */ 68 | virtual gr::trellis::fsm FSM() const = 0; 69 | /*! 70 | * \return The data blocks length considered by the decoder. 71 | */ 72 | virtual int K() const = 0; 73 | /*! 74 | * \return The initial state of the encoder (as given by the decoder, -1 75 | * if unspecified). 76 | */ 77 | virtual int S0() const = 0; 78 | /*! 79 | * \return The final state of the encoder (as given by the decoder, -1 if 80 | * unspecified). 81 | */ 82 | virtual int SK() const = 0; 83 | 84 | /*! 85 | * Gives the initial state of the encoder to the decoder (set to -1 if unknown). 86 | */ 87 | virtual void set_S0(int S0) = 0; 88 | /*! 89 | * Gives the final state of the encoder to the decoder (set to -1 if unknown). 90 | */ 91 | virtual void set_SK(int SK) = 0; 92 | 93 | /*! 94 | * \brief Actual Viterbi algorithm implementation 95 | * 96 | * \param I The number of input sequences (e.g. 2 for binary codes). 97 | * \param S The number of states in the trellis. 98 | * \param O The number of output sequences (e.g. 4 for a binary code with a coding efficiency of 1/2). 99 | * \param NS Gives the next state ns of a branch defined by its initial state s 100 | * and its input symbol i : NS[s*I+i]=ns. 101 | * \param OS Gives the output symbol os of a branch defined by its initial state s 102 | * and its input symbol i : OS[s*I+i]=os. 103 | * \param PS Such that PS[s] contains all the previous states having a branch with state s. 104 | * \param PI Such that PI[s] contains all the inputs yielding to state s. 105 | * \param K Length of a block of data. 106 | * \param S0 Initial state of the encoder (set to -1 if unknown). 107 | * \param SK Final state of the encoder (set to -1 if unknown). 108 | * \param in Input euclidean metrics for the algorithm. 109 | * \param out Output decoded sequence. 110 | * 111 | */ 112 | virtual void viterbi_algorithm_volk_branch(int I, int S, int O, 113 | const std::vector &NS, const std::vector &OS, 114 | const std::vector< std::vector > &PS, 115 | const std::vector< std::vector > &PI, int K, int S0, int SK, 116 | const float *in, unsigned char *out) = 0; 117 | }; 118 | 119 | } // namespace lazyviterbi 120 | } // namespace gr 121 | 122 | #endif /* INCLUDED_LAZYVITERBI_VITERBI_VOLK_BRANCH_H */ 123 | 124 | -------------------------------------------------------------------------------- /include/lazyviterbi/viterbi_volk_state.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2019 Alexandre Marquet. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef INCLUDED_LAZYVITERBI_VITERBI_VOLK_STATE_H 22 | #define INCLUDED_LAZYVITERBI_VITERBI_VOLK_STATE_H 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace gr { 30 | namespace lazyviterbi { 31 | 32 | /*! 33 | * \brief A maximum likelihood decoder. 34 | * 35 | * This block implements the Viterbi algorithm in its classical form, 36 | * as way described e.g., in \cite Forney1973. 37 | * In this implementation, Add Compare and Select operations are run 38 | * sequentially, but for each state in parallel. 39 | * 40 | * It can bring significant speedup for trellis where the number of states 41 | * is larger than the number of branches yielding to states. 42 | * 43 | * It takes euclidean metrics as an input and produces decoded sequences. 44 | */ 45 | class LAZYVITERBI_API viterbi_volk_state : virtual public gr::block 46 | { 47 | public: 48 | typedef boost::shared_ptr sptr; 49 | 50 | /*! 51 | * \brief Return a shared_ptr to a new instance of lazyviterbi::viterbi_volk_branch. 52 | * 53 | * To avoid accidental use of raw pointers, lazyviterbi::viterbi_volk_branch's 54 | * constructor is in a private implementation 55 | * class. lazyviterbi::viterbi_volk_branch::make is the public interface for 56 | * creating new instances. 57 | * 58 | * \param FSM Trellis of the code. 59 | * \param K Length of a block of data. 60 | * \param S0 Initial state of the encoder (set to -1 if unknown). 61 | * \param SK Final state of the encoder (set to -1 if unknown). 62 | */ 63 | static sptr make(const gr::trellis::fsm &FSM, int K, int S0, int SK); 64 | 65 | /*! 66 | * \return The trellis used by the decoder. 67 | */ 68 | virtual gr::trellis::fsm FSM() const = 0; 69 | /*! 70 | * \return The data blocks length considered by the decoder. 71 | */ 72 | virtual int K() const = 0; 73 | /*! 74 | * \return The initial state of the encoder (as given by the decoder, -1 75 | * if unspecified). 76 | */ 77 | virtual int S0() const = 0; 78 | /*! 79 | * \return The final state of the encoder (as given by the decoder, -1 if 80 | * unspecified). 81 | */ 82 | virtual int SK() const = 0; 83 | 84 | /*! 85 | * Gives the initial state of the encoder to the decoder (set to -1 if unknown). 86 | */ 87 | virtual void set_S0(int S0) = 0; 88 | /*! 89 | * Gives the final state of the encoder to the decoder (set to -1 if unknown). 90 | */ 91 | virtual void set_SK(int SK) = 0; 92 | 93 | /*! 94 | * \brief Actual Viterbi algorithm implementation 95 | * 96 | * \param I The number of input sequences (e.g. 2 for binary codes). 97 | * \param S The number of states in the trellis. 98 | * \param O The number of output sequences (e.g. 4 for a binary code with a coding efficiency of 1/2). 99 | * \param NS Gives the next state ns of a branch defined by its initial state s 100 | * and its input symbol i : NS[s*I+i]=ns. 101 | * \param OS Gives the output symbol os of a branch defined by its initial state s 102 | * and its input symbol i : OS[s*I+i]=os. 103 | * \param PS Such that PS[s] contains all the previous states having a branch with state s. 104 | * \param PI Such that PI[s] contains all the inputs yielding to state s. 105 | * \param K Length of a block of data. 106 | * \param S0 Initial state of the encoder (set to -1 if unknown). 107 | * \param SK Final state of the encoder (set to -1 if unknown). 108 | * \param in Input euclidean metrics for the algorithm. 109 | * \param out Output decoded sequence. 110 | * 111 | */ 112 | virtual void viterbi_algorithm_volk_state(int I, int S, int O, 113 | const std::vector &NS, const std::vector &OS, 114 | const std::vector< std::vector > &PS, 115 | const std::vector< std::vector > &PI, int K, int S0, int SK, 116 | const float *in, unsigned char *out) = 0; 117 | }; 118 | 119 | } // namespace lazyviterbi 120 | } // namespace gr 121 | 122 | #endif /* INCLUDED_LAZYVITERBI_VITERBI_VOLK_STATE_H */ 123 | 124 | -------------------------------------------------------------------------------- /lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011,2012,2016,2018,2019 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-lazyviterbi 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | 21 | ######################################################################## 22 | # Setup library 23 | ######################################################################## 24 | include(GrPlatform) #define LIB_SUFFIX 25 | list(APPEND lazyviterbi_sources 26 | viterbi_impl.cc 27 | viterbi_volk_branch_impl.cc 28 | viterbi_volk_state_impl.cc 29 | lazy_viterbi_impl.cc 30 | dynamic_viterbi_impl.cc ) 31 | 32 | set(lazyviterbi_sources "${lazyviterbi_sources}" PARENT_SCOPE) 33 | if(NOT lazyviterbi_sources) 34 | MESSAGE(STATUS "No C++ sources... skipping lib/") 35 | return() 36 | endif(NOT lazyviterbi_sources) 37 | 38 | add_library(gnuradio-lazyviterbi SHARED ${lazyviterbi_sources}) 39 | target_link_libraries(gnuradio-lazyviterbi gnuradio::gnuradio-runtime gnuradio::gnuradio-trellis) 40 | target_include_directories(gnuradio-lazyviterbi 41 | PUBLIC $ 42 | PUBLIC $ 43 | ) 44 | set_target_properties(gnuradio-lazyviterbi PROPERTIES DEFINE_SYMBOL "gnuradio_lazyviterbi_EXPORTS") 45 | 46 | if(APPLE) 47 | set_target_properties(gnuradio-lazyviterbi PROPERTIES 48 | INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib" 49 | ) 50 | endif(APPLE) 51 | 52 | ######################################################################## 53 | # Install built library files 54 | ######################################################################## 55 | include(GrMiscUtils) 56 | GR_LIBRARY_FOO(gnuradio-lazyviterbi) 57 | 58 | ######################################################################## 59 | # Print summary 60 | ######################################################################## 61 | message(STATUS "Using install prefix: ${CMAKE_INSTALL_PREFIX}") 62 | message(STATUS "Building for version: ${VERSION} / ${LIBVER}") 63 | 64 | ######################################################################## 65 | # Build and register unit test 66 | ######################################################################## 67 | include(GrTest) 68 | 69 | # If your unit tests require special include paths, add them here 70 | #include_directories() 71 | # List all files that contain Boost.UTF unit tests here 72 | list(APPEND test_lazyviterbi_sources 73 | ) 74 | # Anything we need to link to for the unit tests go here 75 | list(APPEND GR_TEST_TARGET_DEPS gnuradio-lazyviterbi) 76 | 77 | if(NOT test_lazyviterbi_sources) 78 | MESSAGE(STATUS "No C++ unit tests... skipping") 79 | return() 80 | endif(NOT test_lazyviterbi_sources) 81 | 82 | foreach(qa_file ${test_lazyviterbi_sources}) 83 | GR_ADD_CPP_TEST("lazyviterbi_${qa_file}" 84 | ${CMAKE_CURRENT_SOURCE_DIR}/${qa_file} 85 | ) 86 | endforeach(qa_file) 87 | -------------------------------------------------------------------------------- /lib/dynamic_viterbi_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2017-2018 Free Software Foundation, Inc. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include "dynamic_viterbi_impl.h" 27 | 28 | namespace gr { 29 | namespace lazyviterbi { 30 | 31 | dynamic_viterbi::sptr 32 | dynamic_viterbi::make(const gr::trellis::fsm &FSM, int K, int S0, int SK, float thres) 33 | { 34 | return gnuradio::get_initial_sptr 35 | (new dynamic_viterbi_impl(FSM, K, S0, SK, thres)); 36 | } 37 | 38 | /* 39 | * The private constructor 40 | */ 41 | dynamic_viterbi_impl::dynamic_viterbi_impl(const gr::trellis::fsm &FSM, int K, int S0, int SK, float thres) 42 | : gr::block("dynamic_viterbi", 43 | gr::io_signature::make(1, -1, sizeof(float)), 44 | gr::io_signature::make(1, -1, sizeof(char))), 45 | d_FSM(FSM), d_K(K), d_S0(S0), d_SK(SK), d_is_lazy(true), d_thres(thres), 46 | d_lazy_block(FSM, K, S0, SK), d_viterbi_block(FSM, K, S0, SK) 47 | { 48 | set_relative_rate(1.0 / ((double)d_FSM.O())); 49 | set_output_multiple(d_K); 50 | } 51 | 52 | void 53 | dynamic_viterbi_impl::set_S0(int S0) 54 | { 55 | gr::thread::scoped_lock guard(d_setlock); 56 | 57 | d_S0 = S0; 58 | d_lazy_block.set_S0(S0); 59 | d_viterbi_block.set_S0(S0); 60 | } 61 | 62 | void 63 | dynamic_viterbi_impl::set_SK(int SK) 64 | { 65 | gr::thread::scoped_lock guard(d_setlock); 66 | 67 | d_SK = SK; 68 | d_viterbi_block.set_SK(SK); 69 | } 70 | 71 | void 72 | dynamic_viterbi_impl::set_thres(float thres) 73 | { 74 | gr::thread::scoped_lock guard(d_setlock); 75 | 76 | d_thres = thres; 77 | } 78 | 79 | void 80 | dynamic_viterbi_impl::forecast (int noutput_items, gr_vector_int &ninput_items_required) 81 | { 82 | int input_required = d_FSM.O() * noutput_items; 83 | unsigned ninputs = ninput_items_required.size(); 84 | for(unsigned int i = 0; i < ninputs; i++) { 85 | ninput_items_required[i] = input_required; 86 | } 87 | } 88 | 89 | int 90 | dynamic_viterbi_impl::general_work (int noutput_items, 91 | gr_vector_int &ninput_items, 92 | gr_vector_const_void_star &input_items, 93 | gr_vector_void_star &output_items) 94 | { 95 | gr::thread::scoped_lock guard(d_setlock); 96 | int nstreams = input_items.size(); 97 | int nblocks = noutput_items / d_K; 98 | 99 | for(int m = 0; m < nstreams; m++) { 100 | const float *in = (const float*)input_items[m]; 101 | unsigned char *out = (unsigned char*)output_items[m]; 102 | 103 | for(int n = 0; n < nblocks; n++) { 104 | choose_algo(&(in[n*d_K*d_FSM.O()]), d_K, d_FSM.O()); 105 | 106 | if(d_is_lazy) { 107 | d_lazy_block.lazy_viterbi_algorithm(d_FSM.I(), d_FSM.S(), d_FSM.O(), 108 | d_FSM.NS(), d_FSM.OS(), d_K, d_S0, d_SK, &(in[n*d_K*d_FSM.O()]), 109 | &(out[n*d_K])); 110 | } 111 | else { 112 | d_viterbi_block.viterbi_algorithm(d_FSM.I(), d_FSM.S(), d_FSM.O(), 113 | d_FSM.NS(), d_FSM.OS(), d_FSM.PS(), d_FSM.PI(), d_K, d_S0, d_SK, 114 | &(in[n*d_K*d_FSM.O()]), &(out[n*d_K])); 115 | } 116 | } 117 | } 118 | 119 | consume_each (d_FSM.O() * noutput_items); 120 | return noutput_items; 121 | } 122 | 123 | void 124 | dynamic_viterbi_impl::choose_algo(const float *metrics, int K, int O) 125 | { 126 | float acc_max=0.0, acc_min=0.0; 127 | const float* metrics_end = metrics + K*O; 128 | 129 | while(metrics < metrics_end) { 130 | //Find min_element 131 | acc_min += *std::min_element(metrics, metrics+O); 132 | 133 | //Find max_element 134 | acc_max += *std::max_element(metrics, metrics+O); 135 | 136 | //Update pointer on metrics 137 | metrics += O; 138 | } 139 | 140 | if(acc_max/acc_min > d_thres) { 141 | d_is_lazy = true; 142 | } 143 | else { 144 | d_is_lazy = false; 145 | } 146 | } 147 | 148 | } /* namespace lazyviterbi */ 149 | } /* namespace gr */ 150 | 151 | -------------------------------------------------------------------------------- /lib/dynamic_viterbi_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2017-2018 Free Software Foundation, Inc. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef INCLUDED_LAZYVITERBI_DYNAMIC_VITERBI_IMPL_H 22 | #define INCLUDED_LAZYVITERBI_DYNAMIC_VITERBI_IMPL_H 23 | 24 | #include 25 | #include 26 | #include "lazy_viterbi_impl.h" 27 | #include "viterbi_impl.h" 28 | 29 | namespace gr { 30 | namespace lazyviterbi { 31 | 32 | class dynamic_viterbi_impl : public dynamic_viterbi 33 | { 34 | private: 35 | lazy_viterbi_impl d_lazy_block; 36 | viterbi_impl d_viterbi_block; 37 | bool d_is_lazy; 38 | float d_thres; 39 | 40 | gr::trellis::fsm d_FSM; 41 | int d_K; 42 | int d_S0; 43 | int d_SK; 44 | 45 | public: 46 | dynamic_viterbi_impl(const gr::trellis::fsm &FSM, int K, int S0, int SK, float thres); 47 | 48 | gr::trellis::fsm FSM() const { return d_FSM; } 49 | int K() const { return d_K; } 50 | int S0() const { return d_S0; } 51 | int SK() const { return d_SK; } 52 | float thres() const { return d_thres; } 53 | bool is_lazy() const { return d_is_lazy; } 54 | 55 | void set_S0(int S0); 56 | void set_SK(int SK); 57 | void set_thres(float thres); 58 | 59 | // Where all the action really happens 60 | void forecast (int noutput_items, gr_vector_int &ninput_items_required); 61 | 62 | int general_work(int noutput_items, 63 | gr_vector_int &ninput_items, 64 | gr_vector_const_void_star &input_items, 65 | gr_vector_void_star &output_items); 66 | 67 | void choose_algo(const float *metrics, int K, int O); 68 | }; 69 | 70 | } // namespace lazyviterbi 71 | } // namespace gr 72 | 73 | #endif /* INCLUDED_LAZYVITERBI_DYNAMIC_VITERBI_IMPL_H */ 74 | 75 | -------------------------------------------------------------------------------- /lib/lazy_viterbi_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2017-2018 Free Software Foundation, Inc. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include "lazy_viterbi_impl.h" 27 | 28 | namespace gr { 29 | namespace lazyviterbi { 30 | 31 | lazy_viterbi::sptr 32 | lazy_viterbi::make(const gr::trellis::fsm &FSM, int K, int S0, int SK) 33 | { 34 | return gnuradio::get_initial_sptr 35 | (new lazy_viterbi_impl(FSM, K, S0, SK)); 36 | } 37 | 38 | /* 39 | * The private constructor 40 | */ 41 | lazy_viterbi_impl::lazy_viterbi_impl(const gr::trellis::fsm &FSM, int K, int S0, int SK) 42 | : gr::block("lazy_viterbi", 43 | gr::io_signature::make(1, -1, sizeof(float)), 44 | gr::io_signature::make(1, -1, sizeof(char))), 45 | d_FSM(FSM), d_K(K), d_metrics(K*d_FSM.O()) 46 | { 47 | struct node new_node = {0, -1, false}; //{prev_state_idx, prev_input, expanded} 48 | 49 | //S0 and SK must represent a state of the trellis 50 | if(S0 >= 0 || S0 < d_FSM.S()) { 51 | d_S0 = S0; 52 | } 53 | else { 54 | d_S0 = -1; 55 | } 56 | 57 | if(SK >= K || SK < d_FSM.S()) { 58 | d_SK = SK; 59 | } 60 | else { 61 | d_SK = -1; 62 | } 63 | 64 | //Allocate expanded and shadow nodes containers 65 | d_shadow_nodes.resize(256); //256=2^8=2^sizeof(uint8_t) 66 | d_real_nodes.resize((d_K+1)*d_FSM.S()); 67 | //Set all real nodes to non-expanded 68 | for(std::vector::iterator it=d_real_nodes.begin() ; it != d_real_nodes.end() ; ++it) { 69 | (*it).expanded=false; 70 | } 71 | 72 | set_relative_rate(1.0 / ((double)d_FSM.O())); 73 | set_output_multiple(d_K); 74 | } 75 | 76 | void 77 | lazy_viterbi_impl::set_S0(int S0) 78 | { 79 | gr::thread::scoped_lock guard(d_setlock); 80 | d_S0 = S0; 81 | } 82 | 83 | void 84 | lazy_viterbi_impl::set_SK(int SK) 85 | { 86 | gr::thread::scoped_lock guard(d_setlock); 87 | d_SK = SK; 88 | } 89 | 90 | void 91 | lazy_viterbi_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required) 92 | { 93 | int input_required = d_FSM.O() * noutput_items; 94 | unsigned ninputs = ninput_items_required.size(); 95 | for(unsigned int i = 0; i < ninputs; i++) { 96 | ninput_items_required[i] = input_required; 97 | } 98 | } 99 | 100 | int 101 | lazy_viterbi_impl::general_work (int noutput_items, 102 | gr_vector_int &ninput_items, 103 | gr_vector_const_void_star &input_items, 104 | gr_vector_void_star &output_items) 105 | { 106 | gr::thread::scoped_lock guard(d_setlock); 107 | int nstreams = input_items.size(); 108 | int nblocks = noutput_items / d_K; 109 | 110 | for(int m = 0; m < nstreams; m++) { 111 | const float *in = (const float*)input_items[m]; 112 | unsigned char *out = (unsigned char*)output_items[m]; 113 | 114 | for(int n = 0; n < nblocks; n++) { 115 | lazy_viterbi_algorithm(d_FSM.I(), d_FSM.S(), d_FSM.O(), d_FSM.NS(), 116 | d_FSM.OS(), d_K, d_S0, d_SK, &(in[n*d_K*d_FSM.O()]), &(out[n*d_K])); 117 | } 118 | } 119 | 120 | consume_each(d_FSM.O() * noutput_items); 121 | return noutput_items; 122 | } 123 | 124 | struct minus_cast : public std::binary_function { 125 | uint8_t operator() (float a, float b) const {return (uint8_t)(a-b);} 126 | }; 127 | 128 | void 129 | lazy_viterbi_impl::lazy_viteri_metrics_norm(const float *in, uint8_t* metrics, 130 | int K, int O) 131 | { 132 | float min_metric = 0; 133 | 134 | for(float *in_k=(float*)in ; in_k < in + K*O ; in_k += O) { 135 | //Find min_element 136 | min_metric=*std::min_element(in_k, in_k+O); 137 | 138 | //Remove it from metrics 139 | std::transform(in_k, in_k+O, metrics, std::bind2nd(minus_cast(), min_metric)); 140 | 141 | metrics += O; 142 | } 143 | } 144 | 145 | void 146 | lazy_viterbi_impl::lazy_viterbi_algorithm(int I, int S, int O, const std::vector &NS, 147 | const std::vector &OS, int K, int S0, int SK, const float *in, 148 | unsigned char *out) 149 | { 150 | //***INIT***// 151 | std::vector::iterator metrics_os_it; 152 | uint8_t min_dist_idx = 0; 153 | struct node new_node; 154 | struct shadow_node new_shadow, curr_shadow; 155 | std::vector::iterator expanded_it; 156 | std::vector::const_iterator NS_it, OS_it; 157 | 158 | //If exist put initial node in the shadow queue, 159 | //otherwise, put every nodes a time_idx==0 in it 160 | if(S0 != -1) { 161 | new_shadow.time_idx=0; 162 | new_shadow.state_idx=S0; 163 | new_shadow.prev_state_idx=0; 164 | new_shadow.prev_input=-1; 165 | 166 | d_shadow_nodes[0].push_back(new_shadow); 167 | } 168 | else { 169 | //For each state 170 | for(int s=0 ; s < S ; ++s) { 171 | new_shadow.time_idx=0; 172 | new_shadow.state_idx=s; 173 | new_shadow.prev_state_idx=0; 174 | new_shadow.prev_input=-1; 175 | 176 | d_shadow_nodes[0].push_back(new_shadow); 177 | } 178 | } 179 | 180 | //***NORMALIZE METRICS***// 181 | lazy_viteri_metrics_norm(in, &d_metrics[0], K, O); 182 | 183 | //***FIND SHORTEST PATH***// 184 | do { 185 | //Select another candidate if this node has already been expanded 186 | do { 187 | //Find minimum distance index 188 | while(d_shadow_nodes[min_dist_idx].empty()) { 189 | ++min_dist_idx; 190 | } 191 | 192 | //Retrieve a candidate at minimum distance 193 | curr_shadow = d_shadow_nodes[min_dist_idx].back(); 194 | d_shadow_nodes[min_dist_idx].pop_back(); 195 | 196 | //Update iterator 197 | expanded_it = d_real_nodes.begin() + curr_shadow.time_idx*S 198 | + curr_shadow.state_idx; 199 | } while((*expanded_it).expanded); 200 | 201 | //At this point, we are sure curr_shadow will be expanded 202 | (*expanded_it).expanded=true; 203 | (*expanded_it).prev_input=curr_shadow.prev_input; 204 | (*expanded_it).prev_state_idx=curr_shadow.prev_state_idx; 205 | 206 | //Scan all neighbors of the last expanded node 207 | //Create a shadow neighbor node (pt 1) 208 | new_shadow.time_idx=curr_shadow.time_idx+1; 209 | new_shadow.prev_state_idx=curr_shadow.state_idx; 210 | 211 | //Initialize iterators 212 | expanded_it += S - curr_shadow.state_idx; //real_nodes[curr_shadow.time_idx*S] 213 | metrics_os_it = d_metrics.begin() + curr_shadow.time_idx*O; //metrics[curr_shadow.time_idx*O] 214 | NS_it = NS.begin() + curr_shadow.state_idx*I; //NS[curr_shadow.state_idx*I] 215 | OS_it = OS.begin() + curr_shadow.state_idx*I; //OS[curr_shadow.state_idx*I] 216 | 217 | //For all neighbors 218 | for(int i=0 ; i < I ; ++i) { 219 | //Create a shadow neighbor node (pt 2) 220 | new_shadow.state_idx=*NS_it; 221 | new_shadow.prev_input=i; 222 | 223 | //Add non-expanded neighbors as shadow nodes 224 | if((*(expanded_it + new_shadow.state_idx)).expanded == false) { 225 | d_shadow_nodes[(uint8_t)(min_dist_idx 226 | + *(metrics_os_it + *OS_it) 227 | )].push_back(new_shadow); 228 | } 229 | 230 | //Increment iterators 231 | ++NS_it; 232 | ++OS_it; 233 | } 234 | } while(curr_shadow.time_idx != K && (SK == -1 || curr_shadow.state_idx == SK)); 235 | 236 | //***TRACEBACK***// 237 | new_node.prev_input = curr_shadow.prev_input; 238 | new_node.prev_state_idx = curr_shadow.prev_state_idx; 239 | expanded_it = d_real_nodes.begin() + (K-1)*S; //Place expanded_it at the last time index 240 | for(unsigned char* out_k=out + K-1 ; out_k >= out ; --out_k) { 241 | *out_k = (unsigned char)new_node.prev_input; 242 | new_node = *(expanded_it + new_node.prev_state_idx); 243 | 244 | expanded_it -= S; 245 | } 246 | 247 | //Clear expanded and shadow nodes containers 248 | for(size_t i=0 ; i<256 ; ++i) { 249 | d_shadow_nodes[i].clear(); 250 | } 251 | 252 | for(std::vector::iterator it=d_real_nodes.begin() ; it != d_real_nodes.end() ; ++it) { 253 | (*it).expanded=false; 254 | } 255 | } 256 | 257 | } /* namespace lazyviterbi */ 258 | } /* namespace gr */ 259 | 260 | -------------------------------------------------------------------------------- /lib/lazy_viterbi_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2017-2018 Free Software Foundation, Inc. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef INCLUDED_LAZYVITERBI_LAZY_VITERBI_IMPL_H 22 | #define INCLUDED_LAZYVITERBI_LAZY_VITERBI_IMPL_H 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | #include "node.h" 29 | 30 | namespace gr { 31 | namespace lazyviterbi { 32 | 33 | class lazy_viterbi_impl : public lazy_viterbi 34 | { 35 | private: 36 | gr::trellis::fsm d_FSM; 37 | int d_K; 38 | int d_S0; 39 | int d_SK; 40 | 41 | /* 42 | * Real nodes, to be addressed by real_nodes[time_index*d_FSM.S() + state_index] 43 | */ 44 | std::vector d_real_nodes; 45 | /* 46 | * Shadow nodes. First dimension is used to make a circular buffer of 256 47 | * vectors (corresponding to the 256 possible values of branch metrics). 48 | * The vector nested stores shadow_nodes whose incoming branch have same 49 | * metrics. 50 | */ 51 | std::vector > d_shadow_nodes; 52 | //Store path metrics 53 | std::vector d_metrics; 54 | 55 | public: 56 | lazy_viterbi_impl(const gr::trellis::fsm &FSM, int K, int S0, int SK); 57 | 58 | gr::trellis::fsm FSM() const { return d_FSM; } 59 | int K() const { return d_K; } 60 | int S0() const { return d_S0; } 61 | int SK() const { return d_SK; } 62 | 63 | void set_S0(int S0); 64 | void set_SK(int SK); 65 | 66 | void forecast (int noutput_items, gr_vector_int &ninput_items_required); 67 | 68 | int general_work(int noutput_items, gr_vector_int &ninput_items, 69 | gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); 70 | 71 | void lazy_viteri_metrics_norm(const float *in, uint8_t* metrics, int K, int O); 72 | 73 | void lazy_viterbi_algorithm(int I, int S, int O, const std::vector &NS, 74 | const std::vector &OS, int K, int S0, int SK, const float *in, 75 | unsigned char *out); 76 | }; 77 | 78 | } // namespace lazyviterbi 79 | } // namespace gr 80 | 81 | #endif /* INCLUDED_LAZYVITERBI_LAZY_VITERBI_IMPL_H */ 82 | 83 | -------------------------------------------------------------------------------- /lib/node.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2017 Free Software Foundation, Inc. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef INCLUDED_LAZYVITERBI_NODE_H 22 | #define INCLUDED_LAZYVITERBI_NODE_H 23 | 24 | #include 25 | #include 26 | 27 | namespace gr { 28 | namespace lazyviterbi { 29 | /*! 30 | * \struct node "Structure for real nodes." 31 | * 32 | * Contains the previous state and previous 33 | * input sequence (identifying the branch) leading to itself. 34 | * The identifying information of the node itself in the trellis must be 35 | * handled by its container. 36 | */ 37 | struct node 38 | { 39 | /*! 40 | * Index of the previous state on the shortest path. 41 | */ 42 | unsigned int prev_state_idx; 43 | /*! 44 | * Previous input leading to this node. 45 | */ 46 | int prev_input; 47 | 48 | /*! 49 | * Wether or note this nodes has been expanded. 50 | */ 51 | bool expanded; 52 | }; 53 | 54 | /*! 55 | * \struct node "Structure for shadow nodes." 56 | * 57 | * Contains its identifying information (time and state indexes), as well as 58 | * the previous state and previous input sequence (identifying the branch) 59 | * leading to itself. 60 | */ 61 | struct shadow_node 62 | { 63 | /*! 64 | * Index of the previous state on the shortest path. 65 | */ 66 | unsigned int prev_state_idx; 67 | /*! 68 | * Previous input leading to this node. 69 | */ 70 | int prev_input; 71 | 72 | /*! 73 | * Time index of the node. 74 | */ 75 | unsigned int time_idx; 76 | /*! 77 | * State identifier of the node. 78 | */ 79 | unsigned int state_idx; 80 | }; 81 | } // namespace lazyviterbi 82 | } // namespace gr 83 | 84 | #endif /* INCLUDED_LAZYVITERBI_NODE_H */ 85 | 86 | -------------------------------------------------------------------------------- /lib/qa_lazyviterbi.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Free Software Foundation, Inc. 3 | * 4 | * This file is part of GNU Radio 5 | * 6 | * GNU Radio is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 3, or (at your option) 9 | * any later version. 10 | * 11 | * GNU Radio is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with GNU Radio; see the file COPYING. If not, write to 18 | * the Free Software Foundation, Inc., 51 Franklin Street, 19 | * Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | /* 23 | * This class gathers together all the test cases for the gr-filter 24 | * directory into a single test suite. As you create new test cases, 25 | * add them here. 26 | */ 27 | 28 | #include "qa_lazyviterbi.h" 29 | 30 | CppUnit::TestSuite * 31 | qa_lazyviterbi::suite() 32 | { 33 | CppUnit::TestSuite *s = new CppUnit::TestSuite("lazyviterbi"); 34 | 35 | return s; 36 | } 37 | -------------------------------------------------------------------------------- /lib/qa_lazyviterbi.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2017 Free Software Foundation, Inc. 4 | * 5 | * This file is part of GNU Radio 6 | * 7 | * GNU Radio is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3, or (at your option) 10 | * any later version. 11 | * 12 | * GNU Radio is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with GNU Radio; see the file COPYING. If not, write to 19 | * the Free Software Foundation, Inc., 51 Franklin Street, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #ifndef _QA_LAZYVITERBI_H_ 24 | #define _QA_LAZYVITERBI_H_ 25 | 26 | #include 27 | #include 28 | 29 | //! collect all the tests for the gr-filter directory 30 | 31 | class __GR_ATTR_EXPORT qa_lazyviterbi 32 | { 33 | public: 34 | //! return suite of tests for all of gr-filter directory 35 | static CppUnit::TestSuite *suite(); 36 | }; 37 | 38 | #endif /* _QA_LAZYVITERBI_H_ */ 39 | -------------------------------------------------------------------------------- /lib/test_lazyviterbi.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2017 Free Software Foundation, Inc. 4 | * 5 | * This file is part of GNU Radio 6 | * 7 | * GNU Radio is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 3, or (at your option) 10 | * any later version. 11 | * 12 | * GNU Radio is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with GNU Radio; see the file COPYING. If not, write to 19 | * the Free Software Foundation, Inc., 51 Franklin Street, 20 | * Boston, MA 02110-1301, USA. 21 | */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | #include "config.h" 25 | #endif 26 | 27 | #include 28 | #include 29 | 30 | #include 31 | #include "qa_lazyviterbi.h" 32 | #include 33 | #include 34 | 35 | int 36 | main (int argc, char **argv) 37 | { 38 | CppUnit::TextTestRunner runner; 39 | std::ofstream xmlfile(get_unittest_path("lazyviterbi.xml").c_str()); 40 | CppUnit::XmlOutputter *xmlout = new CppUnit::XmlOutputter(&runner.result(), xmlfile); 41 | 42 | runner.addTest(qa_lazyviterbi::suite()); 43 | runner.setOutputter(xmlout); 44 | 45 | bool was_successful = runner.run("", false); 46 | 47 | return was_successful ? 0 : 1; 48 | } 49 | -------------------------------------------------------------------------------- /lib/viterbi_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2018 Free Software Foundation, Inc. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include "viterbi_impl.h" 27 | 28 | namespace gr { 29 | namespace lazyviterbi { 30 | 31 | viterbi::sptr 32 | viterbi::make(const gr::trellis::fsm &FSM, int K, int S0, int SK) 33 | { 34 | return gnuradio::get_initial_sptr 35 | (new viterbi_impl(FSM, K, S0, SK)); 36 | } 37 | 38 | /* 39 | * The private constructor 40 | */ 41 | viterbi_impl::viterbi_impl(const gr::trellis::fsm &FSM, int K, int S0, int SK) 42 | : gr::block("viterbi", 43 | gr::io_signature::make(1, -1, sizeof(float)), 44 | gr::io_signature::make(1, -1, sizeof(char))), 45 | d_FSM(FSM), d_K(K), d_ordered_OS(FSM.S()*FSM.I()), 46 | d_alpha_prev(FSM.S()), d_alpha_curr(FSM.S()), d_trace(K*FSM.S()) 47 | { 48 | //S0 and SK must represent a state of the trellis 49 | if(S0 >= 0 || S0 < d_FSM.S()) { 50 | d_S0 = S0; 51 | } 52 | else { 53 | d_S0 = -1; 54 | } 55 | 56 | if(SK >= K || SK < d_FSM.S()) { 57 | d_SK = SK; 58 | } 59 | else { 60 | d_SK = -1; 61 | } 62 | 63 | int I = d_FSM.I(); 64 | int S = d_FSM.S(); 65 | std::vector< std::vector > PS = d_FSM.PS(); 66 | std::vector< std::vector > PI = d_FSM.PI(); 67 | std::vector OS = d_FSM.OS(); 68 | 69 | //Compute ordered_OS 70 | std::vector::iterator ordered_OS_it = d_ordered_OS.begin(); 71 | 72 | for(int s=0 ; s < S ; ++s) { 73 | for(size_t i=0 ; i<(PS[s]).size() ; ++i) { 74 | *(ordered_OS_it++) = OS[PS[s][i]*I + PI[s][i]]; 75 | } 76 | } 77 | 78 | set_relative_rate(1.0 / ((double)d_FSM.O())); 79 | set_output_multiple(d_K); 80 | } 81 | 82 | void 83 | viterbi_impl::set_S0(int S0) 84 | { 85 | gr::thread::scoped_lock guard(d_setlock); 86 | d_S0 = S0; 87 | } 88 | 89 | void 90 | viterbi_impl::set_SK(int SK) 91 | { 92 | gr::thread::scoped_lock guard(d_setlock); 93 | d_SK = SK; 94 | } 95 | 96 | void 97 | viterbi_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required) 98 | { 99 | int input_required = d_FSM.O() * noutput_items; 100 | unsigned ninputs = ninput_items_required.size(); 101 | for(unsigned int i = 0; i < ninputs; i++) { 102 | ninput_items_required[i] = input_required; 103 | } 104 | } 105 | 106 | int 107 | viterbi_impl::general_work (int noutput_items, 108 | gr_vector_int &ninput_items, 109 | gr_vector_const_void_star &input_items, 110 | gr_vector_void_star &output_items) 111 | { 112 | gr::thread::scoped_lock guard(d_setlock); 113 | int nstreams = input_items.size(); 114 | int nblocks = noutput_items / d_K; 115 | 116 | for(int m = 0; m < nstreams; m++) { 117 | const float *in = (const float*)input_items[m]; 118 | unsigned char *out = (unsigned char*)output_items[m]; 119 | 120 | for(int n = 0; n < nblocks; n++) { 121 | viterbi_algorithm(d_FSM.I(), d_FSM.S(), d_FSM.O(), d_FSM.NS(), 122 | d_ordered_OS, d_FSM.PS(), d_FSM.PI(), d_K, d_S0, d_SK, 123 | &(in[n*d_K*d_FSM.O()]), &(out[n*d_K])); 124 | } 125 | } 126 | 127 | consume_each(d_FSM.O() * noutput_items); 128 | return noutput_items; 129 | } 130 | 131 | void 132 | viterbi_impl::viterbi_algorithm(int I, int S, int O, const std::vector &NS, 133 | const std::vector &ordered_OS, const std::vector< std::vector > &PS, 134 | const std::vector< std::vector > &PI, int K, int S0, int SK, 135 | const float *in, unsigned char *out) 136 | { 137 | int tb_state, pidx; 138 | float can_metric = std::numeric_limits::max(); 139 | float min_metric = std::numeric_limits::max(); 140 | 141 | std::vector::iterator alpha_curr_it; 142 | std::vector::const_iterator PS_it; 143 | std::vector::iterator trace_it = d_trace.begin(); 144 | std::vector::const_iterator ordered_OS_it = ordered_OS.begin(); 145 | 146 | //Initialize traceback vector 147 | std::fill(d_trace.begin(), d_trace.end(), 0); 148 | 149 | //If initial state was specified 150 | if(S0 != -1) { 151 | std::fill(d_alpha_prev.begin(), d_alpha_prev.end(), 152 | std::numeric_limits::max()); 153 | d_alpha_prev[S0] = 0.0; 154 | } 155 | else { 156 | std::fill(d_alpha_prev.begin(), d_alpha_prev.end(), 0.0); 157 | } 158 | 159 | for(float* in_k=(float*)in ; in_k < (float*)in + K*O ; in_k += O) { 160 | //Current path metric iterator 161 | alpha_curr_it = d_alpha_curr.begin(); 162 | ordered_OS_it = ordered_OS.begin(); 163 | 164 | //Reset minimum metric (used for normalization) 165 | min_metric = std::numeric_limits::max(); 166 | 167 | //For each state 168 | for(std::vector< std::vector >::const_iterator PS_s = PS.begin() ; 169 | PS_s != PS.end() ; ++PS_s) { 170 | //Iterators for previous state 171 | PS_it=(*PS_s).begin(); 172 | 173 | //Pre-loop 174 | //*d_alpha_curr_it = alpha_prev[PS[s][i]] + in_k[OS[PS[s][i]*I + PI[s][i]]]; 175 | *alpha_curr_it = d_alpha_prev[*(PS_it++)] + in_k[*(ordered_OS_it++)]; 176 | min_metric = (*alpha_curr_it < min_metric)?*alpha_curr_it:min_metric; 177 | 178 | //Loop 179 | for(size_t i=1 ; i< (*PS_s).size() ; ++i) { 180 | //ADD 181 | //can_metric = alpha_prev[PS[s][i]] + in_k[OS[PS[s][i]*I + PI[s][i]]]; 182 | can_metric = d_alpha_prev[*(PS_it++)] + in_k[*(ordered_OS_it++)]; 183 | 184 | //COMPARE 185 | if(can_metric < *alpha_curr_it) { 186 | //SELECT 187 | *alpha_curr_it = can_metric; 188 | min_metric = (*alpha_curr_it < min_metric)?*alpha_curr_it:min_metric; 189 | 190 | //Store previous input index for traceback 191 | *trace_it = i; 192 | } 193 | } 194 | 195 | //Update iterators 196 | ++trace_it; 197 | ++alpha_curr_it; 198 | } 199 | 200 | //Metrics normalization 201 | std::transform(d_alpha_curr.begin(), d_alpha_curr.end(), 202 | d_alpha_curr.begin(), 203 | std::bind2nd(std::minus(), min_metric)); 204 | 205 | //At this point, current path metrics becomes previous path metrics 206 | d_alpha_prev.swap(d_alpha_curr); 207 | } 208 | 209 | //If final state was specified 210 | if(SK != -1) { 211 | tb_state = SK; 212 | } 213 | else{ 214 | //at this point, alpha_prev contains the path metrics of states after time K 215 | tb_state = (int)(min_element(d_alpha_prev.begin(), d_alpha_prev.end()) - d_alpha_prev.begin()); 216 | } 217 | 218 | //Traceback 219 | trace_it = d_trace.end() - S; //place trace_it at the last time index 220 | 221 | for(unsigned char* out_k = out+K-1 ; out_k >= out ; --out_k) { 222 | //Retrieve previous input index from trace 223 | pidx=*(trace_it + tb_state); 224 | //Update trace_it for next output symbol 225 | trace_it -= S; 226 | 227 | //Output previous input 228 | *out_k = (unsigned char) PI[tb_state][pidx]; 229 | 230 | //Update tb_state with the previous state on the shortest path 231 | tb_state = PS[tb_state][pidx]; 232 | } 233 | } 234 | 235 | } /* namespace lazyviterbi */ 236 | } /* namespace gr */ 237 | 238 | -------------------------------------------------------------------------------- /lib/viterbi_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2018 Free Software Foundation, Inc. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef INCLUDED_LAZYVITERBI_VITERBI_IMPL_H 22 | #define INCLUDED_LAZYVITERBI_VITERBI_IMPL_H 23 | 24 | #include 25 | 26 | namespace gr { 27 | namespace lazyviterbi { 28 | 29 | class viterbi_impl : public viterbi 30 | { 31 | private: 32 | gr::trellis::fsm d_FSM; //Trellis description 33 | int d_K; //Number of trellis sections 34 | int d_S0; //Initial state idx (-1 if unknown) 35 | int d_SK; //Final state idx (-1 if unknown) 36 | 37 | //Same as d_FSM.OS(), but re-ordered in the following way: 38 | //d_ordered_OS[s*I+i] = d_FSM.OS()[d_FSM.PS()[s][i]*I + d_FSM.PI()[s][i]] 39 | std::vector d_ordered_OS; 40 | 41 | //Store current state metrics 42 | std::vector d_alpha_prev; 43 | //Store next state metrics 44 | std::vector d_alpha_curr; 45 | //Traceback vector 46 | std::vector d_trace; 47 | 48 | public: 49 | viterbi_impl(const gr::trellis::fsm &FSM, int K, int S0, int SK); 50 | 51 | gr::trellis::fsm FSM() const { return d_FSM; } 52 | int K() const { return d_K; } 53 | int S0() const { return d_S0; } 54 | int SK() const { return d_SK; } 55 | 56 | void set_S0(int S0); 57 | void set_SK(int SK); 58 | 59 | void forecast (int noutput_items, gr_vector_int &ninput_items_required); 60 | 61 | int general_work(int noutput_items, gr_vector_int &ninput_items, 62 | gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); 63 | 64 | void viterbi_algorithm(int I, int S, int O, const std::vector &NS, 65 | const std::vector &ordered_OS, const std::vector< std::vector > &PS, 66 | const std::vector< std::vector > &PI, int K, int S0, int SK, 67 | const float *in, unsigned char *out); 68 | }; 69 | 70 | } // namespace lazyviterbi 71 | } // namespace gr 72 | 73 | #endif /* INCLUDED_LAZYVITERBI_VITERBI_IMPL_H */ 74 | 75 | -------------------------------------------------------------------------------- /lib/viterbi_volk_branch_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2019 Alexandre Marquet. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include "viterbi_volk_branch_impl.h" 27 | 28 | namespace gr { 29 | namespace lazyviterbi { 30 | 31 | viterbi_volk_branch::sptr 32 | viterbi_volk_branch::make(const gr::trellis::fsm &FSM, int K, int S0, int SK) 33 | { 34 | return gnuradio::get_initial_sptr 35 | (new viterbi_volk_branch_impl(FSM, K, S0, SK)); 36 | } 37 | 38 | /* 39 | * The private constructor 40 | */ 41 | viterbi_volk_branch_impl::viterbi_volk_branch_impl(const gr::trellis::fsm &FSM, int K, int S0, int SK) 42 | : gr::block("viterbi_volk_branch", 43 | gr::io_signature::make(1, -1, sizeof(float)), 44 | gr::io_signature::make(1, -1, sizeof(char))), 45 | d_FSM(FSM), d_K(K), d_ordered_OS(FSM.S()*FSM.I()), 46 | d_ordered_PS(FSM.S()*FSM.I()) 47 | { 48 | //S0 and SK must represent a state of the trellis 49 | if(S0 >= 0 || S0 < d_FSM.S()) { 50 | d_S0 = S0; 51 | } 52 | else { 53 | d_S0 = -1; 54 | } 55 | 56 | if(SK >= K || SK < d_FSM.S()) { 57 | d_SK = SK; 58 | } 59 | else { 60 | d_SK = -1; 61 | } 62 | 63 | int I = d_FSM.I(); 64 | int S = d_FSM.S(); 65 | std::vector< std::vector > PS = d_FSM.PS(); 66 | std::vector< std::vector > PI = d_FSM.PI(); 67 | std::vector OS = d_FSM.OS(); 68 | 69 | //Compute ordered_OS and max_size_PS_s 70 | std::vector::iterator ordered_OS_it = d_ordered_OS.begin(); 71 | std::vector::iterator ordered_PS_it = d_ordered_PS.begin(); 72 | 73 | d_n_metrics = 0; 74 | for(int s=0 ; s < S ; ++s) { 75 | for(size_t i=0 ; i<(PS[s]).size() ; ++i) { 76 | *(ordered_OS_it++) = OS[PS[s][i]*I + PI[s][i]]; 77 | *(ordered_PS_it++) = PS[s][i]; 78 | ++d_n_metrics; 79 | } 80 | } 81 | 82 | //Memory reservations 83 | d_alpha_curr = (float*)volk_malloc(S*sizeof(float), volk_get_alignment()); 84 | 85 | d_alpha_prev = (float*)volk_malloc(S*sizeof(float), volk_get_alignment()); 86 | 87 | d_can_metrics = (float*)volk_malloc(d_n_metrics*sizeof(float), 88 | volk_get_alignment()); 89 | 90 | d_ordered_in_k = (float*)volk_malloc(d_n_metrics * sizeof(float), 91 | volk_get_alignment()); 92 | 93 | d_trace = (uint32_t*)volk_malloc(K*S*sizeof(uint32_t), 94 | volk_get_alignment()); 95 | 96 | set_relative_rate(1.0 / ((double)d_FSM.O())); 97 | set_output_multiple(d_K); 98 | } 99 | 100 | viterbi_volk_branch_impl::~viterbi_volk_branch_impl() 101 | { 102 | volk_free(d_alpha_prev); 103 | volk_free(d_alpha_curr); 104 | volk_free(d_can_metrics); 105 | volk_free(d_ordered_in_k); 106 | volk_free(d_trace); 107 | } 108 | 109 | void 110 | viterbi_volk_branch_impl::set_S0(int S0) 111 | { 112 | gr::thread::scoped_lock guard(d_setlock); 113 | d_S0 = S0; 114 | } 115 | 116 | void 117 | viterbi_volk_branch_impl::set_SK(int SK) 118 | { 119 | gr::thread::scoped_lock guard(d_setlock); 120 | d_SK = SK; 121 | } 122 | 123 | void 124 | viterbi_volk_branch_impl::forecast(int noutput_items, gr_vector_int &ninput_items_required) 125 | { 126 | int input_required = d_FSM.O() * noutput_items; 127 | unsigned ninputs = ninput_items_required.size(); 128 | for(unsigned int i = 0; i < ninputs; i++) { 129 | ninput_items_required[i] = input_required; 130 | } 131 | } 132 | 133 | int 134 | viterbi_volk_branch_impl::general_work (int noutput_items, 135 | gr_vector_int &ninput_items, 136 | gr_vector_const_void_star &input_items, 137 | gr_vector_void_star &output_items) 138 | { 139 | gr::thread::scoped_lock guard(d_setlock); 140 | int nstreams = input_items.size(); 141 | int nblocks = noutput_items / d_K; 142 | 143 | for(int m = 0; m < nstreams; m++) { 144 | const float *in = (const float*)input_items[m]; 145 | unsigned char *out = (unsigned char*)output_items[m]; 146 | 147 | for(int n = 0; n < nblocks; n++) { 148 | viterbi_algorithm_volk_branch(d_FSM.I(), d_FSM.S(), d_FSM.O(), 149 | d_FSM.NS(), d_ordered_OS, d_FSM.PS(), d_FSM.PI(), d_K, d_S0, d_SK, 150 | &(in[n*d_K*d_FSM.O()]), &(out[n*d_K])); 151 | } 152 | } 153 | 154 | consume_each(d_FSM.O() * noutput_items); 155 | return noutput_items; 156 | } 157 | 158 | void 159 | viterbi_volk_branch_impl::compute_all_metrics(const float *alpha_prev, 160 | const float *in_k, float *can_metrics) 161 | { 162 | std::vector::const_iterator ordered_OS_it = d_ordered_OS.begin(); 163 | std::vector::const_iterator ordered_PS_it = d_ordered_PS.begin(); 164 | 165 | float *ordered_in_k_it = d_ordered_in_k; 166 | float *can_metrics_it = can_metrics; 167 | 168 | for(size_t i=0 ; i < d_n_metrics ; ++i) { 169 | *(can_metrics_it++) = alpha_prev[*(ordered_PS_it++)]; 170 | *(ordered_in_k_it++) = in_k[*(ordered_OS_it++)]; 171 | } 172 | 173 | volk_32f_x2_subtract_32f(can_metrics, can_metrics, d_ordered_in_k, d_n_metrics); 174 | } 175 | 176 | //Volk optimized implementation adapted when the number of branch between 177 | //pairs of states is greater than the number of states. 178 | void 179 | viterbi_volk_branch_impl::viterbi_algorithm_volk_branch(int I, int S, int O, 180 | const std::vector &NS, const std::vector &ordered_OS, 181 | const std::vector< std::vector > &PS, 182 | const std::vector< std::vector > &PI, int K, int S0, int SK, 183 | const float *in, unsigned char *out) 184 | { 185 | int tb_state, pidx; 186 | size_t n_branch_state = 0; 187 | 188 | uint32_t *max_idx = (uint32_t*)volk_malloc(sizeof(uint32_t), 189 | volk_get_alignment()); 190 | 191 | std::vector< std::vector >::const_iterator PS_s; 192 | 193 | float *alpha_curr_it; 194 | float *can_metrics_it = d_can_metrics; 195 | uint32_t *trace_it = d_trace; 196 | 197 | //If initial state was specified 198 | if(S0 != -1) { 199 | std::fill(d_alpha_prev, d_alpha_prev + S, 200 | -std::numeric_limits::max()); 201 | d_alpha_prev[S0] = 0.0; 202 | } 203 | else { 204 | std::fill(d_alpha_prev, d_alpha_prev + S, 0.0); 205 | } 206 | 207 | for(float* in_k=(float*)in ; in_k < (float*)in + K*O ; in_k += O) { 208 | //ADD 209 | compute_all_metrics(d_alpha_prev, in_k, d_can_metrics); 210 | 211 | alpha_curr_it = d_alpha_curr; 212 | PS_s = PS.begin(); 213 | //COMPARE 214 | for(int s = 0 ; s < S ; ++s) { 215 | n_branch_state = (*PS_s++).size(); 216 | 217 | volk_32f_index_max_32u(trace_it, can_metrics_it, n_branch_state); 218 | 219 | //SELECT 220 | *(alpha_curr_it++) = can_metrics_it[*(trace_it++)]; 221 | 222 | //Update pointer 223 | can_metrics_it += n_branch_state; 224 | } 225 | 226 | //At this point, current path metrics becomes previous path metrics 227 | std::swap(d_alpha_prev, d_alpha_curr); 228 | 229 | //Metrics normalization 230 | volk_32f_index_max_32u(max_idx, d_alpha_prev, S); 231 | std::transform(d_alpha_prev, d_alpha_prev + S, d_alpha_prev, 232 | std::bind2nd(std::minus(), d_alpha_prev[*max_idx])); 233 | 234 | //Update iterators 235 | can_metrics_it = d_can_metrics; 236 | } 237 | 238 | //If final state was specified 239 | if(SK != -1) { 240 | tb_state = SK; 241 | } 242 | else{ 243 | //at this point, d_alpha_prev contains the path metrics of states after time K 244 | tb_state = (int)(*max_idx); 245 | } 246 | 247 | //Traceback 248 | trace_it -= S; //place trace at the last time index 249 | 250 | for(unsigned char* out_k = out+K-1 ; out_k >= out ; --out_k) { 251 | //Retrieve previous input index from d_trace 252 | pidx=*(trace_it + tb_state); 253 | //Update d_trace_it for next output symbol 254 | trace_it -= S; 255 | 256 | //Output previous input 257 | *out_k = (unsigned char) PI[tb_state][pidx]; 258 | 259 | //Update tb_state with the previous state on the shortest path 260 | tb_state = PS[tb_state][pidx]; 261 | } 262 | 263 | //Dealocate max_idx 264 | volk_free(max_idx); 265 | } 266 | 267 | } /* namespace lazyviterbi */ 268 | } /* namespace gr */ 269 | 270 | -------------------------------------------------------------------------------- /lib/viterbi_volk_branch_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2019 Alexandre Marquet. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef INCLUDED_LAZYVITERBI_VITERBI_VOLK_BRANCH_IMPL_H 22 | #define INCLUDED_LAZYVITERBI_VITERBI_VOLK_BRANCH_IMPL_H 23 | 24 | #include 25 | #include 26 | 27 | namespace gr { 28 | namespace lazyviterbi { 29 | 30 | class viterbi_volk_branch_impl : public viterbi_volk_branch 31 | { 32 | private: 33 | gr::trellis::fsm d_FSM; //Trellis description 34 | int d_K; //Number of trellis sections 35 | int d_S0; //Initial state idx (-1 if unknown) 36 | int d_SK; //Final state idx (-1 if unknown) 37 | 38 | size_t d_n_metrics; //Number of branches in a trellis section 39 | 40 | //Same as d_FSM.OS(), but re-ordered in the following way: 41 | //d_ordered_OS[s*I+i] = d_FSM.OS()[d_FSM.PS()[s][i]*I + d_FSM.PI()[s][i]] 42 | std::vector d_ordered_OS; 43 | //Same as d_FSM.PS(), but flattened: 44 | //d_ordered_PS[s*I+i] = d_FSM.PS()[s][i] 45 | std::vector d_ordered_PS; 46 | //Input metrics, ordered as d_ordered_in_k[i] = in_k[d_ordered_OS[i]] 47 | float *d_ordered_in_k; 48 | 49 | //Store current state metrics 50 | float *d_alpha_curr; 51 | //Store next state metrics 52 | float *d_alpha_prev; 53 | //Store next state candidate metrics 54 | float *d_can_metrics; 55 | //Traceback vector 56 | uint32_t *d_trace; 57 | 58 | protected: 59 | void compute_all_metrics(const float *alpha_prev, const float *in_k, 60 | float *can_metrics); 61 | 62 | public: 63 | viterbi_volk_branch_impl(const gr::trellis::fsm &FSM, int K, int S0, int SK); 64 | ~viterbi_volk_branch_impl(); 65 | 66 | gr::trellis::fsm FSM() const { return d_FSM; } 67 | int K() const { return d_K; } 68 | int S0() const { return d_S0; } 69 | int SK() const { return d_SK; } 70 | 71 | void set_S0(int S0); 72 | void set_SK(int SK); 73 | 74 | void forecast (int noutput_items, gr_vector_int &ninput_items_required); 75 | 76 | int general_work(int noutput_items, gr_vector_int &ninput_items, 77 | gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); 78 | 79 | void viterbi_algorithm_volk_branch(int I, int S, int O, const std::vector &NS, 80 | const std::vector &ordered_OS, const std::vector< std::vector > &PS, 81 | const std::vector< std::vector > &PI, int K, int S0, int SK, 82 | const float *in, unsigned char *out); 83 | }; 84 | 85 | } // namespace lazyviterbi 86 | } // namespace gr 87 | 88 | #endif /* INCLUDED_LAZYVITERBI_VITERBI_VOLK_BRANCH_IMPL_H */ 89 | 90 | -------------------------------------------------------------------------------- /lib/viterbi_volk_state_impl.cc: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2019 Alexandre Marquet. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include 26 | #include "viterbi_volk_state_impl.h" 27 | 28 | namespace gr { 29 | namespace lazyviterbi { 30 | 31 | viterbi_volk_state::sptr 32 | viterbi_volk_state::make(const gr::trellis::fsm &FSM, int K, int S0, int SK) 33 | { 34 | return gnuradio::get_initial_sptr 35 | (new viterbi_volk_state_impl(FSM, K, S0, SK)); 36 | } 37 | 38 | /* 39 | * The private constructor 40 | */ 41 | viterbi_volk_state_impl::viterbi_volk_state_impl(const gr::trellis::fsm &FSM, int K, int S0, int SK) 42 | : gr::block("viterbi_volk_state", 43 | gr::io_signature::make(1, -1, sizeof(float)), 44 | gr::io_signature::make(1, -1, sizeof(char))), 45 | d_FSM(FSM), d_K(K), d_ordered_OS(FSM.S()*FSM.I()), d_ordered_PS(FSM.S()*FSM.I()) 46 | { 47 | //S0 and SK must represent a state of the trellis 48 | if(S0 >= 0 || S0 < d_FSM.S()) { 49 | d_S0 = S0; 50 | } 51 | else { 52 | d_S0 = -1; 53 | } 54 | 55 | if(SK >= K || SK < d_FSM.S()) { 56 | d_SK = SK; 57 | } 58 | else { 59 | d_SK = -1; 60 | } 61 | 62 | int I = d_FSM.I(); 63 | int S = d_FSM.S(); 64 | std::vector< std::vector > PS = d_FSM.PS(); 65 | std::vector< std::vector > PI = d_FSM.PI(); 66 | std::vector OS = d_FSM.OS(); 67 | 68 | d_max_size_PS_s = 0; 69 | std::vector::iterator ordered_OS_it = d_ordered_OS.begin(); 70 | std::vector::iterator ordered_PS_it = d_ordered_PS.begin(); 71 | 72 | for(int s=0 ; s < S ; ++s) { 73 | if ((PS[s]).size() > d_max_size_PS_s) { 74 | d_max_size_PS_s = (PS[s]).size(); 75 | } 76 | } 77 | 78 | for(size_t i=0 ; i::const_iterator ordered_OS_it = d_ordered_OS.begin(); 173 | std::vector::const_iterator ordered_PS_it = d_ordered_PS.begin(); 174 | 175 | float *ordered_in_k_it = d_ordered_in_k; 176 | float *can_metrics_it = can_metrics; 177 | 178 | for(size_t i=0 ; i < n_pts ; ++i) { 179 | if (!(*ordered_PS_it < 0)) { 180 | *(can_metrics_it++) = alpha_prev[*(ordered_PS_it++)]; 181 | *(ordered_in_k_it++) = in_k[*(ordered_OS_it++)]; 182 | } 183 | else { 184 | *(can_metrics_it++) = std::numeric_limits::max(); 185 | *(ordered_in_k_it++) = std::numeric_limits::max(); 186 | ordered_PS_it++; 187 | ordered_OS_it++; 188 | } 189 | } 190 | 191 | volk_32f_x2_subtract_32f(can_metrics, can_metrics, d_ordered_in_k, n_pts); 192 | } 193 | 194 | //Volk optimized implementation adapted when the number of branch between 195 | //pairs of states is inferior to the number of states. 196 | void 197 | viterbi_volk_state_impl::viterbi_algorithm_volk_state(int I, int S, int O, 198 | const std::vector &NS, const std::vector &OS, 199 | const std::vector< std::vector > &PS, 200 | const std::vector< std::vector > &PI, int K, int S0, int SK, 201 | const float *in, unsigned char *out) 202 | { 203 | int tb_state, pidx; 204 | //float *min_metric_ptr; 205 | uint32_t *max_idx = (uint32_t*)volk_malloc(sizeof(uint32_t), 206 | volk_get_alignment()); 207 | 208 | //Iterators 209 | int *trace_it = d_trace; 210 | float *can_metrics_it = d_can_metrics; 211 | float *alpha_curr_it; 212 | 213 | //Initialize traceback vector 214 | std::fill(trace_it, trace_it + K*S, 0); 215 | 216 | //If initial state was specified 217 | if(S0 != -1) { 218 | std::fill(d_alpha_prev, d_alpha_prev + S, 219 | -std::numeric_limits::max()); 220 | d_alpha_prev[S0] = 0.0; 221 | } 222 | else { 223 | std::fill(d_alpha_prev, d_alpha_prev + S, 0.0); 224 | } 225 | 226 | for(float* in_k=(float*)in ; in_k < (float*)in + K*O ; in_k += O) { 227 | //ADD 228 | compute_all_metrics(d_alpha_prev, in_k, d_can_metrics); 229 | 230 | //Pre-loop 231 | std::copy(d_can_metrics, d_can_metrics + S, d_alpha_curr); 232 | can_metrics_it += S; 233 | 234 | //Loop 235 | for(size_t i=1 ; i < d_max_size_PS_s ; ++i) { 236 | //COMPARE 237 | //d_alpha_curr[s] = max(d_alpha_curr[s], d_can_metrics[s]) 238 | volk_32f_x2_max_32f(d_alpha_curr, d_alpha_curr, can_metrics_it, S); 239 | 240 | //SELECT 241 | alpha_curr_it = d_alpha_curr; 242 | for(int s=0 ; s < S ; ++s) { 243 | *(trace_it++) = (*(can_metrics_it++) == (*alpha_curr_it++))?i:*trace_it; 244 | } 245 | 246 | //Update iterators 247 | trace_it -= S; 248 | } 249 | 250 | //At this point, current path metrics becomes previous path metrics 251 | std::swap(d_alpha_prev, d_alpha_curr); 252 | 253 | //Metrics normalization 254 | volk_32f_index_max_32u(max_idx, d_alpha_prev, S); 255 | std::transform(d_alpha_prev, d_alpha_prev + S, d_alpha_prev, 256 | std::bind2nd(std::minus(), d_alpha_prev[*max_idx])); 257 | 258 | //Update iterators 259 | trace_it += S; 260 | can_metrics_it = d_can_metrics; 261 | } 262 | 263 | //If final state was specified 264 | if(SK != -1) { 265 | tb_state = SK; 266 | } 267 | else{ 268 | //at this point, alpha_prev contains the path metrics of states after time K 269 | tb_state = (int)(*max_idx); 270 | } 271 | 272 | //Traceback 273 | trace_it -= S; //place trace at the last time index 274 | 275 | for(unsigned char* out_k = out+K-1 ; out_k >= out ; --out_k) { 276 | //Retrieve previous input index from trace 277 | pidx=*(trace_it + tb_state); 278 | //Update trace for next output symbol 279 | trace_it -= S; 280 | 281 | //Output previous input 282 | *out_k = (unsigned char) PI[tb_state][pidx]; 283 | 284 | //Update tb_state with the previous state on the shortest path 285 | tb_state = PS[tb_state][pidx]; 286 | } 287 | 288 | //Dealocate max_idx 289 | volk_free(max_idx); 290 | } 291 | 292 | 293 | } /* namespace lazyviterbi */ 294 | } /* namespace gr */ 295 | 296 | -------------------------------------------------------------------------------- /lib/viterbi_volk_state_impl.h: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | /* 3 | * Copyright 2019 Alexandre Marquet. 4 | * 5 | * This is free software; you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation; either version 3, or (at your option) 8 | * any later version. 9 | * 10 | * This software is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this software; see the file COPYING. If not, write to 17 | * the Free Software Foundation, Inc., 51 Franklin Street, 18 | * Boston, MA 02110-1301, USA. 19 | */ 20 | 21 | #ifndef INCLUDED_LAZYVITERBI_VITERBI_VOLK_STATE_IMPL_H 22 | #define INCLUDED_LAZYVITERBI_VITERBI_VOLK_STATE_IMPL_H 23 | 24 | #include 25 | #include 26 | 27 | namespace gr { 28 | namespace lazyviterbi { 29 | 30 | class viterbi_volk_state_impl : public viterbi_volk_state 31 | { 32 | private: 33 | gr::trellis::fsm d_FSM; //Trellis description 34 | int d_K; //Number of trellis sections 35 | int d_S0; //Initial state idx (-1 if unknown) 36 | int d_SK; //Final state idx (-1 if unknown) 37 | 38 | //Same as d_FSM.OS(), but re-ordered in the following way: 39 | //d_ordered_OS[i*S+s] = d_FSM.OS()[d_FSM.PS()[s][i]*I + d_FSM.PI()[s][i]] 40 | std::vector d_ordered_OS; 41 | //Same as d_FSM.PS(), but flattened: 42 | //d_ordered_PS[i*S+s] = d_FSM.PS()[s][i] 43 | std::vector d_ordered_PS; 44 | //Input metrics, ordered as d_ordered_in_k[i] = in_k[d_ordered_OS[i]] 45 | float *d_ordered_in_k; 46 | //Max size of PS[s] 47 | size_t d_max_size_PS_s; 48 | 49 | //Store current state metrics 50 | float *d_alpha_curr; 51 | //Store next state metrics 52 | float *d_alpha_prev; 53 | //Store next state candidate metrics 54 | float *d_can_metrics; 55 | //Traceback vector 56 | int *d_trace; 57 | 58 | protected: 59 | void compute_all_metrics(const float *alpha_prev, const float *in_k, 60 | float *can_metrics); 61 | 62 | public: 63 | viterbi_volk_state_impl(const gr::trellis::fsm &FSM, int K, int S0, int SK); 64 | ~viterbi_volk_state_impl(); 65 | 66 | gr::trellis::fsm FSM() const { return d_FSM; } 67 | int K() const { return d_K; } 68 | int S0() const { return d_S0; } 69 | int SK() const { return d_SK; } 70 | 71 | void set_S0(int S0); 72 | void set_SK(int SK); 73 | 74 | void forecast (int noutput_items, gr_vector_int &ninput_items_required); 75 | 76 | int general_work(int noutput_items, gr_vector_int &ninput_items, 77 | gr_vector_const_void_star &input_items, gr_vector_void_star &output_items); 78 | 79 | void viterbi_algorithm_volk_state(int I, int S, int O, const std::vector &NS, 80 | const std::vector &OS, const std::vector< std::vector > &PS, 81 | const std::vector< std::vector > &PI, int K, int S0, int SK, 82 | const float *in, unsigned char *out); 83 | }; 84 | 85 | } // namespace lazyviterbi 86 | } // namespace gr 87 | 88 | #endif /* INCLUDED_LAZYVITERBI_VITERBI_VOLK_STATE_IMPL_H */ 89 | 90 | -------------------------------------------------------------------------------- /python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-lazyviterbi 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | 21 | ######################################################################## 22 | # Include python install macros 23 | ######################################################################## 24 | include(GrPython) 25 | if(NOT PYTHONINTERP_FOUND) 26 | return() 27 | endif() 28 | 29 | ######################################################################## 30 | # Install python sources 31 | ######################################################################## 32 | GR_PYTHON_INSTALL( 33 | FILES 34 | __init__.py 35 | DESTINATION ${GR_PYTHON_DIR}/lazyviterbi 36 | ) 37 | 38 | ######################################################################## 39 | # Handle the unit tests 40 | ######################################################################## 41 | include(GrTest) 42 | 43 | set(GR_TEST_TARGET_DEPS gnuradio-lazyviterbi) 44 | set(GR_TEST_PYTHON_DIRS ${CMAKE_BINARY_DIR}/swig) 45 | GR_ADD_TEST(qa_viterbi ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_viterbi.py) 46 | GR_ADD_TEST(qa_lazy_viterbi ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_lazy_viterbi.py) 47 | GR_ADD_TEST(qa_dynamic_viterbi ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_dynamic_viterbi.py) 48 | GR_ADD_TEST(qa_viterbi_volk_branch ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_viterbi_volk_branch.py) 49 | GR_ADD_TEST(qa_viterbi_volk_state ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/qa_viterbi_volk_state.py) 50 | -------------------------------------------------------------------------------- /python/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2008,2009 Free Software Foundation, Inc. 3 | # 4 | # This application is free software; you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation; either version 3, or (at your option) 7 | # any later version. 8 | # 9 | # This application is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along 15 | # with this program; if not, write to the Free Software Foundation, Inc., 16 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | # 18 | 19 | # The presence of this file turns this directory into a Python package 20 | 21 | ''' 22 | This is the GNU Radio LAZYVITERBI module. Place your Python package 23 | description here (python/__init__.py). 24 | ''' 25 | from __future__ import unicode_literals 26 | 27 | # import swig generated symbols into the lazyviterbi namespace 28 | try: 29 | # this might fail if the module is python-only 30 | from .lazyviterbi_swig import * 31 | except ImportError: 32 | pass 33 | 34 | # import any pure python here 35 | # 36 | -------------------------------------------------------------------------------- /python/build_utils.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2004,2009,2012 Free Software Foundation, Inc. 3 | # 4 | # This file is part of GNU Radio 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | 22 | """Misc utilities used at build time 23 | """ 24 | 25 | import re, os, os.path 26 | from build_utils_codes import * 27 | 28 | 29 | # set srcdir to the directory that contains Makefile.am 30 | try: 31 | srcdir = os.environ['srcdir'] 32 | except KeyError, e: 33 | srcdir = "." 34 | srcdir = srcdir + '/' 35 | 36 | # set do_makefile to either true or false dependeing on the environment 37 | try: 38 | if os.environ['do_makefile'] == '0': 39 | do_makefile = False 40 | else: 41 | do_makefile = True 42 | except KeyError, e: 43 | do_makefile = False 44 | 45 | # set do_sources to either true or false dependeing on the environment 46 | try: 47 | if os.environ['do_sources'] == '0': 48 | do_sources = False 49 | else: 50 | do_sources = True 51 | except KeyError, e: 52 | do_sources = True 53 | 54 | name_dict = {} 55 | 56 | def log_output_name (name): 57 | (base, ext) = os.path.splitext (name) 58 | ext = ext[1:] # drop the leading '.' 59 | 60 | entry = name_dict.setdefault (ext, []) 61 | entry.append (name) 62 | 63 | def open_and_log_name (name, dir): 64 | global do_sources 65 | if do_sources: 66 | f = open (name, dir) 67 | else: 68 | f = None 69 | log_output_name (name) 70 | return f 71 | 72 | def expand_template (d, template_filename, extra = ""): 73 | '''Given a dictionary D and a TEMPLATE_FILENAME, expand template into output file 74 | ''' 75 | global do_sources 76 | output_extension = extract_extension (template_filename) 77 | template = open_src (template_filename, 'r') 78 | output_name = d['NAME'] + extra + '.' + output_extension 79 | log_output_name (output_name) 80 | if do_sources: 81 | output = open (output_name, 'w') 82 | do_substitution (d, template, output) 83 | output.close () 84 | template.close () 85 | 86 | def output_glue (dirname): 87 | output_makefile_fragment () 88 | output_ifile_include (dirname) 89 | 90 | def output_makefile_fragment (): 91 | global do_makefile 92 | if not do_makefile: 93 | return 94 | # overwrite the source, which must be writable; this should have been 95 | # checked for beforehand in the top-level Makefile.gen.gen . 96 | f = open (os.path.join (os.environ.get('gendir', os.environ.get('srcdir', '.')), 'Makefile.gen'), 'w') 97 | f.write ('#\n# This file is machine generated. All edits will be overwritten\n#\n') 98 | output_subfrag (f, 'h') 99 | output_subfrag (f, 'i') 100 | output_subfrag (f, 'cc') 101 | f.close () 102 | 103 | def output_ifile_include (dirname): 104 | global do_sources 105 | if do_sources: 106 | f = open ('%s_generated.i' % (dirname,), 'w') 107 | f.write ('//\n// This file is machine generated. All edits will be overwritten\n//\n') 108 | files = name_dict.setdefault ('i', []) 109 | files.sort () 110 | f.write ('%{\n') 111 | for file in files: 112 | f.write ('#include <%s>\n' % (file[0:-1] + 'h',)) 113 | f.write ('%}\n\n') 114 | for file in files: 115 | f.write ('%%include <%s>\n' % (file,)) 116 | 117 | def output_subfrag (f, ext): 118 | files = name_dict.setdefault (ext, []) 119 | files.sort () 120 | f.write ("GENERATED_%s =" % (ext.upper ())) 121 | for file in files: 122 | f.write (" \\\n\t%s" % (file,)) 123 | f.write ("\n\n") 124 | 125 | def extract_extension (template_name): 126 | # template name is something like: GrFIRfilterXXX.h.t 127 | # we return everything between the penultimate . and .t 128 | mo = re.search (r'\.([a-z]+)\.t$', template_name) 129 | if not mo: 130 | raise ValueError, "Incorrectly formed template_name '%s'" % (template_name,) 131 | return mo.group (1) 132 | 133 | def open_src (name, mode): 134 | global srcdir 135 | return open (os.path.join (srcdir, name), mode) 136 | 137 | def do_substitution (d, in_file, out_file): 138 | def repl (match_obj): 139 | key = match_obj.group (1) 140 | # print key 141 | return d[key] 142 | 143 | inp = in_file.read () 144 | out = re.sub (r"@([a-zA-Z0-9_]+)@", repl, inp) 145 | out_file.write (out) 146 | 147 | 148 | 149 | copyright = '''/* -*- c++ -*- */ 150 | /* 151 | * Copyright 2003,2004 Free Software Foundation, Inc. 152 | * 153 | * This file is part of GNU Radio 154 | * 155 | * GNU Radio is free software; you can redistribute it and/or modify 156 | * it under the terms of the GNU General Public License as published by 157 | * the Free Software Foundation; either version 3, or (at your option) 158 | * any later version. 159 | * 160 | * GNU Radio is distributed in the hope that it will be useful, 161 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 162 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 163 | * GNU General Public License for more details. 164 | * 165 | * You should have received a copy of the GNU General Public License 166 | * along with GNU Radio; see the file COPYING. If not, write to 167 | * the Free Software Foundation, Inc., 51 Franklin Street, 168 | * Boston, MA 02110-1301, USA. 169 | */ 170 | ''' 171 | 172 | def is_complex (code3): 173 | if i_code (code3) == 'c' or o_code (code3) == 'c': 174 | return '1' 175 | else: 176 | return '0' 177 | 178 | 179 | def standard_dict (name, code3, package='gr'): 180 | d = {} 181 | d['NAME'] = name 182 | d['NAME_IMPL'] = name+'_impl' 183 | d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper()) 184 | d['GUARD_NAME_IMPL'] = 'INCLUDED_%s_%s_IMPL_H' % (package.upper(), name.upper()) 185 | d['BASE_NAME'] = re.sub ('^' + package + '_', '', name) 186 | d['SPTR_NAME'] = '%s_sptr' % name 187 | d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten' 188 | d['COPYRIGHT'] = copyright 189 | d['TYPE'] = i_type (code3) 190 | d['I_TYPE'] = i_type (code3) 191 | d['O_TYPE'] = o_type (code3) 192 | d['TAP_TYPE'] = tap_type (code3) 193 | d['IS_COMPLEX'] = is_complex (code3) 194 | return d 195 | 196 | 197 | def standard_dict2 (name, code3, package): 198 | d = {} 199 | d['NAME'] = name 200 | d['BASE_NAME'] = name 201 | d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper()) 202 | d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten' 203 | d['COPYRIGHT'] = copyright 204 | d['TYPE'] = i_type (code3) 205 | d['I_TYPE'] = i_type (code3) 206 | d['O_TYPE'] = o_type (code3) 207 | d['TAP_TYPE'] = tap_type (code3) 208 | d['IS_COMPLEX'] = is_complex (code3) 209 | return d 210 | 211 | def standard_impl_dict2 (name, code3, package): 212 | d = {} 213 | d['NAME'] = name 214 | d['IMPL_NAME'] = name 215 | d['BASE_NAME'] = name.rstrip("impl").rstrip("_") 216 | d['GUARD_NAME'] = 'INCLUDED_%s_%s_H' % (package.upper(), name.upper()) 217 | d['WARNING'] = 'WARNING: this file is machine generated. Edits will be overwritten' 218 | d['COPYRIGHT'] = copyright 219 | d['FIR_TYPE'] = "fir_filter_" + code3 220 | d['CFIR_TYPE'] = "fir_filter_" + code3[0:2] + 'c' 221 | d['TYPE'] = i_type (code3) 222 | d['I_TYPE'] = i_type (code3) 223 | d['O_TYPE'] = o_type (code3) 224 | d['TAP_TYPE'] = tap_type (code3) 225 | d['IS_COMPLEX'] = is_complex (code3) 226 | return d 227 | -------------------------------------------------------------------------------- /python/build_utils_codes.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2004 Free Software Foundation, Inc. 3 | # 4 | # This file is part of GNU Radio 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | 22 | def i_code (code3): 23 | return code3[0] 24 | 25 | def o_code (code3): 26 | if len (code3) >= 2: 27 | return code3[1] 28 | else: 29 | return code3[0] 30 | 31 | def tap_code (code3): 32 | if len (code3) >= 3: 33 | return code3[2] 34 | else: 35 | return code3[0] 36 | 37 | def i_type (code3): 38 | return char_to_type[i_code (code3)] 39 | 40 | def o_type (code3): 41 | return char_to_type[o_code (code3)] 42 | 43 | def tap_type (code3): 44 | return char_to_type[tap_code (code3)] 45 | 46 | 47 | char_to_type = {} 48 | char_to_type['s'] = 'short' 49 | char_to_type['i'] = 'int' 50 | char_to_type['f'] = 'float' 51 | char_to_type['c'] = 'gr_complex' 52 | char_to_type['b'] = 'unsigned char' 53 | -------------------------------------------------------------------------------- /python/qa_dynamic_viterbi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2017 Free Software Foundation, Inc. 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # This software is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this software; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | 22 | from gnuradio import gr, gr_unittest 23 | from gnuradio import blocks 24 | import lazyviterbi_swig as lazyviterbi 25 | 26 | class qa_dynamic_viterbi (gr_unittest.TestCase): 27 | 28 | def setUp (self): 29 | self.tb = gr.top_block () 30 | 31 | def tearDown (self): 32 | self.tb = None 33 | 34 | def test_001_t (self): 35 | # set up fg 36 | self.tb.run () 37 | # check data 38 | 39 | 40 | if __name__ == '__main__': 41 | gr_unittest.run(qa_dynamic_viterbi, "qa_dynamic_viterbi.xml") 42 | -------------------------------------------------------------------------------- /python/qa_lazy_viterbi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2017 Free Software Foundation, Inc. 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # This software is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this software; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | 22 | from gnuradio import gr, gr_unittest 23 | from gnuradio import blocks 24 | import lazyviterbi_swig as lazyviterbi 25 | 26 | class qa_lazy_viterbi (gr_unittest.TestCase): 27 | 28 | def setUp (self): 29 | self.tb = gr.top_block () 30 | 31 | def tearDown (self): 32 | self.tb = None 33 | 34 | def test_001_t (self): 35 | # set up fg 36 | self.tb.run () 37 | # check data 38 | 39 | 40 | if __name__ == '__main__': 41 | gr_unittest.run(qa_lazy_viterbi, "qa_lazy_viterbi.xml") 42 | -------------------------------------------------------------------------------- /python/qa_viterbi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2018 Free Software Foundation, Inc. 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # This software is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this software; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | 22 | from gnuradio import gr, gr_unittest 23 | from gnuradio import blocks 24 | import lazyviterbi_swig as lazyviterbi 25 | 26 | class qa_viterbi (gr_unittest.TestCase): 27 | 28 | def setUp (self): 29 | self.tb = gr.top_block () 30 | 31 | def tearDown (self): 32 | self.tb = None 33 | 34 | def test_001_t (self): 35 | # set up fg 36 | self.tb.run () 37 | # check data 38 | 39 | 40 | if __name__ == '__main__': 41 | gr_unittest.run(qa_viterbi, "qa_viterbi.xml") 42 | -------------------------------------------------------------------------------- /python/qa_viterbi_volk_branch.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2019 Alexandre Marquet. 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # This software is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this software; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | 22 | from gnuradio import gr, gr_unittest 23 | from gnuradio import blocks 24 | import lazyviterbi_swig as lazyviterbi 25 | 26 | class qa_viterbi_volk_branch(gr_unittest.TestCase): 27 | 28 | def setUp(self): 29 | self.tb = gr.top_block() 30 | 31 | def tearDown(self): 32 | self.tb = None 33 | 34 | def test_001_t(self): 35 | # set up fg 36 | self.tb.run() 37 | # check data 38 | 39 | 40 | if __name__ == '__main__': 41 | gr_unittest.run(qa_viterbi_volk_branch) 42 | -------------------------------------------------------------------------------- /python/qa_viterbi_volk_state.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2019 Alexandre Marquet. 5 | # 6 | # This is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # This software is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this software; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | # 21 | 22 | from gnuradio import gr, gr_unittest 23 | from gnuradio import blocks 24 | import lazyviterbi_swig as lazyviterbi 25 | 26 | class qa_viterbi_volk_state(gr_unittest.TestCase): 27 | 28 | def setUp(self): 29 | self.tb = gr.top_block() 30 | 31 | def tearDown(self): 32 | self.tb = None 33 | 34 | def test_001_t(self): 35 | # set up fg 36 | self.tb.run() 37 | # check data 38 | 39 | 40 | if __name__ == '__main__': 41 | gr_unittest.run(qa_viterbi_volk_state) 42 | -------------------------------------------------------------------------------- /swig/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2011 Free Software Foundation, Inc. 2 | # 3 | # This file was generated by gr_modtool, a tool from the GNU Radio framework 4 | # This file is a part of gr-lazyviterbi 5 | # 6 | # GNU Radio is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 3, or (at your option) 9 | # any later version. 10 | # 11 | # GNU Radio is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with GNU Radio; see the file COPYING. If not, write to 18 | # the Free Software Foundation, Inc., 51 Franklin Street, 19 | # Boston, MA 02110-1301, USA. 20 | 21 | ######################################################################## 22 | # Check if there is C++ code at all 23 | ######################################################################## 24 | if(NOT lazyviterbi_sources) 25 | MESSAGE(STATUS "No C++ sources... skipping swig/") 26 | return() 27 | endif(NOT lazyviterbi_sources) 28 | 29 | ######################################################################## 30 | # Include swig generation macros 31 | ######################################################################## 32 | find_package(SWIG) 33 | find_package(PythonLibs) 34 | if(NOT SWIG_FOUND OR NOT PYTHONLIBS_FOUND) 35 | return() 36 | endif() 37 | include(GrSwig) 38 | include(GrPython) 39 | 40 | ######################################################################## 41 | # Setup swig generation 42 | ######################################################################## 43 | set(GR_SWIG_INCLUDE_DIRS $) 44 | set(GR_SWIG_TARGET_DEPS gnuradio::runtime_swig) 45 | 46 | set(GR_SWIG_LIBRARIES gnuradio-lazyviterbi) 47 | 48 | set(GR_SWIG_DOC_FILE ${CMAKE_CURRENT_BINARY_DIR}/lazyviterbi_swig_doc.i) 49 | set(GR_SWIG_DOC_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../include) 50 | 51 | GR_SWIG_MAKE(lazyviterbi_swig lazyviterbi_swig.i) 52 | 53 | ######################################################################## 54 | # Install the build swig module 55 | ######################################################################## 56 | GR_SWIG_INSTALL(TARGETS lazyviterbi_swig DESTINATION ${GR_PYTHON_DIR}/lazyviterbi) 57 | 58 | ######################################################################## 59 | # Install swig .i files for development 60 | ######################################################################## 61 | install( 62 | FILES 63 | lazyviterbi_swig.i 64 | ${CMAKE_CURRENT_BINARY_DIR}/lazyviterbi_swig_doc.i 65 | DESTINATION ${GR_INCLUDE_DIR}/lazyviterbi/swig 66 | ) 67 | -------------------------------------------------------------------------------- /swig/lazyviterbi_swig.i: -------------------------------------------------------------------------------- 1 | /* -*- c++ -*- */ 2 | 3 | #define LAZYVITERBI_API 4 | 5 | %include "gnuradio.i" // the common stuff 6 | 7 | //load generated python docstrings 8 | %include "lazyviterbi_swig_doc.i" 9 | 10 | %{ 11 | #include "lazyviterbi/viterbi.h" 12 | #include "lazyviterbi/lazy_viterbi.h" 13 | #include "lazyviterbi/dynamic_viterbi.h" 14 | #include "lazyviterbi/viterbi_volk_branch.h" 15 | #include "lazyviterbi/viterbi_volk_state.h" 16 | %} 17 | 18 | %include "lazyviterbi/viterbi.h" 19 | GR_SWIG_BLOCK_MAGIC2(lazyviterbi, viterbi); 20 | %include "lazyviterbi/lazy_viterbi.h" 21 | GR_SWIG_BLOCK_MAGIC2(lazyviterbi, lazy_viterbi); 22 | %include "lazyviterbi/dynamic_viterbi.h" 23 | GR_SWIG_BLOCK_MAGIC2(lazyviterbi, dynamic_viterbi); 24 | 25 | %include "lazyviterbi/viterbi_volk_branch.h" 26 | GR_SWIG_BLOCK_MAGIC2(lazyviterbi, viterbi_volk_branch); 27 | %include "lazyviterbi/viterbi_volk_state.h" 28 | GR_SWIG_BLOCK_MAGIC2(lazyviterbi, viterbi_volk_state); 29 | --------------------------------------------------------------------------------