diff options
author | Johannes Demel <ufcsy@student.kit.edu> | 2015-06-18 12:14:32 +0200 |
---|---|---|
committer | Johannes Demel <ufcsy@student.kit.edu> | 2015-09-21 10:45:12 +0200 |
commit | 13592802e792a417b1db511dbb1d0445ff4955c8 (patch) | |
tree | 4ecb7d8f8527f9d501a22d871fcca5e0c4b3f838 | |
parent | 87670ad6f14e61bf4bde6c6e5b18d19b262fe33f (diff) |
polar: SC and SC List decoder implemented in C++
27 files changed, 1865 insertions, 355 deletions
diff --git a/gr-fec/examples/polar_encoder_decoder_chain.grc b/gr-fec/examples/polar_encoder_decoder_chain.grc index c648aea294..7cab62d291 100644 --- a/gr-fec/examples/polar_encoder_decoder_chain.grc +++ b/gr-fec/examples/polar_encoder_decoder_chain.grc @@ -18,7 +18,17 @@ </param> <param> <key>comment</key> - <value></value> + <value># for rough throughput measurements. + + tb = polar_encoder_decoder_chain() + start_time = time.time() + tb.start() + tb.wait() + stop_time = time.time() + samps = 2 ** 22 + diff = stop_time - start_time + throughput = tb.head_samps / diff + print("exe time:", diff, ", with ", tb.head_samps, "samps, throughput: ", throughput)</value> </param> <param> <key>description</key> @@ -74,42 +84,18 @@ </param> </block> <block> - <key>variable_cc_decoder_def</key> - <param> - <key>padding</key> - <value>False</value> - </param> + <key>variable</key> <param> <key>comment</key> <value></value> </param> <param> - <key>k</key> - <value>7</value> - </param> - <param> - <key>dim1</key> - <value>1</value> - </param> - <param> - <key>dim2</key> - <value>1</value> - </param> - <param> <key>_enabled</key> <value>True</value> </param> <param> - <key>state_end</key> - <value>-1</value> - </param> - <param> - <key>framebits</key> - <value>2048</value> - </param> - <param> <key>_coordinate</key> - <value>(640, 35)</value> + <value>(360, 11)</value> </param> <param> <key>_rotation</key> @@ -117,66 +103,42 @@ </param> <param> <key>id</key> - <value>cc_decoder</value> + <value>head_samps</value> </param> <param> <key>value</key> - <value>"ok"</value> - </param> - <param> - <key>ndim</key> - <value>0</value> - </param> - <param> - <key>polys</key> - <value>[79,109]</value> - </param> - <param> - <key>rate</key> - <value>2</value> - </param> - <param> - <key>state_start</key> - <value>0</value> - </param> - <param> - <key>mode</key> - <value>fec.CC_STREAMING</value> + <value>2 ** 22</value> </param> </block> <block> - <key>variable_cc_encoder_def</key> + <key>variable_polar_decoder_sc_def</key> <param> - <key>padding</key> - <value>False</value> - </param> - <param> - <key>comment</key> - <value></value> + <key>num_info_bits</key> + <value>128</value> </param> <param> - <key>k</key> - <value>7</value> + <key>block_size</key> + <value>256</value> </param> <param> - <key>dim1</key> - <value>1</value> + <key>comment</key> + <value></value> </param> <param> - <key>dim2</key> - <value>1</value> + <key>_enabled</key> + <value>True</value> </param> <param> - <key>_enabled</key> - <value>False</value> + <key>frozen_bit_positions</key> + <value>range(128)</value> </param> <param> - <key>framebits</key> - <value>2048</value> + <key>frozen_bit_values</key> + <value>[0] * 128</value> </param> <param> <key>_coordinate</key> - <value>(304, 43)</value> + <value>(864, 555)</value> </param> <param> <key>_rotation</key> @@ -184,27 +146,11 @@ </param> <param> <key>id</key> - <value>cc_encoder</value> - </param> - <param> - <key>ndim</key> - <value>0</value> - </param> - <param> - <key>polys</key> - <value>[79,109]</value> - </param> - <param> - <key>rate</key> - <value>2</value> - </param> - <param> - <key>state_start</key> - <value>0</value> + <value>polar_decoder</value> </param> <param> - <key>mode</key> - <value>fec.CC_STREAMING</value> + <key>is_packed</key> + <value>False</value> </param> </block> <block> @@ -235,7 +181,7 @@ </param> <param> <key>_coordinate</key> - <value>(576, 307)</value> + <value>(192, 451)</value> </param> <param> <key>_rotation</key> @@ -251,7 +197,15 @@ </param> </block> <block> - <key>variable</key> + <key>variable_polar_decoder_sc_list_def</key> + <param> + <key>num_info_bits</key> + <value>128</value> + </param> + <param> + <key>block_size</key> + <value>256</value> + </param> <param> <key>comment</key> <value></value> @@ -261,8 +215,16 @@ <value>True</value> </param> <param> + <key>frozen_bit_positions</key> + <value>range(128)</value> + </param> + <param> + <key>frozen_bit_values</key> + <value>[0,] * 128</value> + </param> + <param> <key>_coordinate</key> - <value>(10, 170)</value> + <value>(608, 539)</value> </param> <param> <key>_rotation</key> @@ -270,11 +232,15 @@ </param> <param> <key>id</key> - <value>samp_rate</value> + <value>polar_scld</value> </param> <param> - <key>value</key> - <value>32000</value> + <key>max_list_size</key> + <value>8</value> + </param> + <param> + <key>is_packed</key> + <value>False</value> </param> </block> <block> @@ -297,7 +263,7 @@ </param> <param> <key>_coordinate</key> - <value>(136, 227)</value> + <value>(0, 323)</value> </param> <param> <key>_rotation</key> @@ -325,7 +291,7 @@ </param> <param> <key>num_samps</key> - <value>2 ** 10</value> + <value>2 ** 10 </value> </param> <param> <key>type</key> @@ -337,7 +303,7 @@ </param> </block> <block> - <key>blocks_char_to_float</key> + <key>blocks_add_const_vxx</key> <param> <key>alias</key> <value></value> @@ -347,16 +313,20 @@ <value></value> </param> <param> + <key>const</key> + <value>1.0</value> + </param> + <param> <key>affinity</key> <value></value> </param> <param> <key>_enabled</key> - <value>False</value> + <value>True</value> </param> <param> <key>_coordinate</key> - <value>(1272, 251)</value> + <value>(752, 347)</value> </param> <param> <key>_rotation</key> @@ -364,7 +334,11 @@ </param> <param> <key>id</key> - <value>blocks_char_to_float_0</value> + <value>blocks_add_const_vxx_0</value> + </param> + <param> + <key>type</key> + <value>float</value> </param> <param> <key>maxoutbuf</key> @@ -375,16 +349,12 @@ <value>0</value> </param> <param> - <key>scale</key> - <value>10</value> - </param> - <param> <key>vlen</key> <value>1</value> </param> </block> <block> - <key>blocks_head</key> + <key>blocks_char_to_float</key> <param> <key>alias</key> <value></value> @@ -399,11 +369,11 @@ </param> <param> <key>_enabled</key> - <value>True</value> + <value>False</value> </param> <param> <key>_coordinate</key> - <value>(1080, 363)</value> + <value>(1112, 347)</value> </param> <param> <key>_rotation</key> @@ -411,7 +381,7 @@ </param> <param> <key>id</key> - <value>blocks_head_0</value> + <value>blocks_char_to_float_0</value> </param> <param> <key>maxoutbuf</key> @@ -422,12 +392,8 @@ <value>0</value> </param> <param> - <key>num_items</key> - <value>2 ** 32</value> - </param> - <param> - <key>type</key> - <value>byte</value> + <key>scale</key> + <value>1.0</value> </param> <param> <key>vlen</key> @@ -435,16 +401,12 @@ </param> </block> <block> - <key>blocks_null_sink</key> + <key>blocks_char_to_float</key> <param> <key>alias</key> <value></value> </param> <param> - <key>bus_conns</key> - <value>[[0,],]</value> - </param> - <param> <key>comment</key> <value></value> </param> @@ -458,7 +420,7 @@ </param> <param> <key>_coordinate</key> - <value>(1256, 368)</value> + <value>(616, 347)</value> </param> <param> <key>_rotation</key> @@ -466,15 +428,19 @@ </param> <param> <key>id</key> - <value>blocks_null_sink_0</value> + <value>blocks_char_to_float_0_0</value> </param> <param> - <key>type</key> - <value>byte</value> + <key>maxoutbuf</key> + <value>0</value> </param> <param> - <key>num_inputs</key> - <value>1</value> + <key>minoutbuf</key> + <value>0</value> + </param> + <param> + <key>scale</key> + <value>-0.5</value> </param> <param> <key>vlen</key> @@ -482,7 +448,7 @@ </param> </block> <block> - <key>blocks_pack_k_bits_bb</key> + <key>blocks_head</key> <param> <key>alias</key> <value></value> @@ -501,7 +467,7 @@ </param> <param> <key>_coordinate</key> - <value>(408, 251)</value> + <value>(944, 459)</value> </param> <param> <key>_rotation</key> @@ -509,11 +475,7 @@ </param> <param> <key>id</key> - <value>blocks_pack_k_bits_bb_0</value> - </param> - <param> - <key>k</key> - <value>8</value> + <value>blocks_head_0</value> </param> <param> <key>maxoutbuf</key> @@ -523,14 +485,30 @@ <key>minoutbuf</key> <value>0</value> </param> + <param> + <key>num_items</key> + <value>head_samps</value> + </param> + <param> + <key>type</key> + <value>byte</value> + </param> + <param> + <key>vlen</key> + <value>1</value> + </param> </block> <block> - <key>blocks_unpack_k_bits_bb</key> + <key>blocks_null_sink</key> <param> <key>alias</key> <value></value> </param> <param> + <key>bus_conns</key> + <value>[[0,],]</value> + </param> + <param> <key>comment</key> <value></value> </param> @@ -544,7 +522,7 @@ </param> <param> <key>_coordinate</key> - <value>(904, 363)</value> + <value>(1160, 464)</value> </param> <param> <key>_rotation</key> @@ -552,23 +530,27 @@ </param> <param> <key>id</key> - <value>blocks_unpack_k_bits_bb_0</value> + <value>blocks_null_sink_0</value> </param> <param> - <key>k</key> - <value>8</value> + <key>type</key> + <value>byte</value> </param> <param> - <key>maxoutbuf</key> - <value>0</value> + <key>num_inputs</key> + <value>1</value> </param> <param> - <key>minoutbuf</key> - <value>0</value> + <key>vlen</key> + <value>1</value> </param> </block> <block> - <key>fec_generic_decoder</key> + <key>fec_extended_decoder</key> + <param> + <key>ann</key> + <value>None</value> + </param> <param> <key>alias</key> <value></value> @@ -582,16 +564,16 @@ <value></value> </param> <param> - <key>decoder</key> - <value>cc_decoder</value> + <key>decoder_list</key> + <value>polar_scld</value> </param> <param> <key>_enabled</key> - <value>False</value> + <value>True</value> </param> <param> <key>_coordinate</key> - <value>(1040, 251)</value> + <value>(872, 323)</value> </param> <param> <key>_rotation</key> @@ -599,11 +581,7 @@ </param> <param> <key>id</key> - <value>fec_generic_decoder_0</value> - </param> - <param> - <key>itype</key> - <value>byte</value> + <value>fec_extended_decoder_0</value> </param> <param> <key>maxoutbuf</key> @@ -614,12 +592,20 @@ <value>0</value> </param> <param> - <key>otype</key> - <value>byte</value> + <key>puncpat</key> + <value>'11'</value> + </param> + <param> + <key>threadtype</key> + <value>none</value> + </param> + <param> + <key>value</key> + <value>fec_extended_decoder</value> </param> </block> <block> - <key>fec_generic_encoder</key> + <key>fec_extended_encoder</key> <param> <key>alias</key> <value></value> @@ -629,20 +615,20 @@ <value></value> </param> <param> - <key>encoder</key> - <value>polar_encoder</value> - </param> - <param> <key>affinity</key> <value></value> </param> <param> <key>_enabled</key> - <value>True</value> + <value>False</value> + </param> + <param> + <key>encoder_list</key> + <value>polar_encoder</value> </param> <param> <key>_coordinate</key> - <value>(576, 251)</value> + <value>(192, 331)</value> </param> <param> <key>_rotation</key> @@ -650,11 +636,7 @@ </param> <param> <key>id</key> - <value>fec_generic_encoder_0</value> - </param> - <param> - <key>itype</key> - <value>byte</value> + <value>fec_extended_encoder_0</value> </param> <param> <key>maxoutbuf</key> @@ -665,8 +647,12 @@ <value>0</value> </param> <param> - <key>otype</key> - <value>byte</value> + <key>puncpat</key> + <value>'11'</value> + </param> + <param> + <key>threadtype</key> + <value>none</value> </param> </block> <block> @@ -732,7 +718,7 @@ </param> <param> <key>_coordinate</key> - <value>(1432, 235)</value> + <value>(1256, 331)</value> </param> <param> <key>gui_hint</key> @@ -1061,55 +1047,55 @@ </block> <connection> <source_block_id>analog_random_source_x_0</source_block_id> - <sink_block_id>blocks_pack_k_bits_bb_0</sink_block_id> + <sink_block_id>blocks_char_to_float_0_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> - <source_block_id>blocks_char_to_float_0</source_block_id> - <sink_block_id>qtgui_time_sink_x_0</sink_block_id> + <source_block_id>analog_random_source_x_0</source_block_id> + <sink_block_id>fec_extended_encoder_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> - <source_block_id>blocks_head_0</source_block_id> - <sink_block_id>blocks_null_sink_0</sink_block_id> + <source_block_id>blocks_add_const_vxx_0</source_block_id> + <sink_block_id>fec_extended_decoder_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> - <source_block_id>blocks_pack_k_bits_bb_0</source_block_id> - <sink_block_id>fec_generic_encoder_0</sink_block_id> + <source_block_id>blocks_char_to_float_0</source_block_id> + <sink_block_id>qtgui_time_sink_x_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> - <source_block_id>blocks_unpack_k_bits_bb_0</source_block_id> - <sink_block_id>blocks_head_0</sink_block_id> + <source_block_id>blocks_char_to_float_0_0</source_block_id> + <sink_block_id>blocks_add_const_vxx_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> - <source_block_id>fec_generic_decoder_0</source_block_id> - <sink_block_id>blocks_char_to_float_0</sink_block_id> + <source_block_id>blocks_head_0</source_block_id> + <sink_block_id>blocks_null_sink_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> - <source_block_id>fec_generic_encoder_0</source_block_id> + <source_block_id>fec_extended_decoder_0</source_block_id> <sink_block_id>blocks_char_to_float_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> - <source_block_id>fec_generic_encoder_0</source_block_id> - <sink_block_id>blocks_unpack_k_bits_bb_0</sink_block_id> + <source_block_id>fec_extended_decoder_0</source_block_id> + <sink_block_id>blocks_head_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> <connection> - <source_block_id>fec_generic_encoder_0</source_block_id> - <sink_block_id>fec_generic_decoder_0</sink_block_id> + <source_block_id>fec_extended_encoder_0</source_block_id> + <sink_block_id>blocks_char_to_float_0_0</sink_block_id> <source_key>0</source_key> <sink_key>0</sink_key> </connection> diff --git a/gr-fec/grc/fec_block_tree.xml b/gr-fec/grc/fec_block_tree.xml index f2f2c5b8f6..d15ef26b63 100644 --- a/gr-fec/grc/fec_block_tree.xml +++ b/gr-fec/grc/fec_block_tree.xml @@ -15,6 +15,8 @@ <block>variable_ldpc_decoder_def</block> <block>variable_tpc_decoder_def</block> <block>variable_dummy_decoder_def</block> + <block>variable_polar_decoder_sc_def</block> + <block>variable_polar_decoder_sc_list_def</block> </cat> <cat> <name>Encoders</name> diff --git a/gr-fec/grc/fec_polar_decoder_sc.xml b/gr-fec/grc/fec_polar_decoder_sc.xml new file mode 100644 index 0000000000..e7cb1eaa48 --- /dev/null +++ b/gr-fec/grc/fec_polar_decoder_sc.xml @@ -0,0 +1,50 @@ +<?xml version="1.0"?> +<block> + <name>POLAR Decoder SC Definition</name> + <key>variable_polar_decoder_sc_def</key> + <import>from gnuradio import fec</import> + <var_make> +self.$(id) = $(id) = fec.polar_decoder_sc.make($block_size, $num_info_bits, $frozen_bit_positions, $frozen_bit_values, $is_packed) + </var_make> + <var_value>fec.polar_decoder_sc.make($block_size, $num_info_bits, $frozen_bit_positions, $frozen_bit_values, $is_packed)</var_value> + <make></make> + + <param> + <name>Packed Bits</name> + <key>is_packed</key> + <value>False</value> + <type>enum</type> + <option> + <name>No</name> + <key>False</key> + </option> + <option> + <name>Yes</name> + <key>True</key> + </option> + </param> + + <param> + <name>Block size (N)</name> + <key>block_size</key> + <type>int</type> + </param> + + <param> + <name>#Info Bits (K)</name> + <key>num_info_bits</key> + <type>int</type> + </param> + + <param> + <name>Frozen Bit Positions</name> + <key>frozen_bit_positions</key> + <type>int_vector</type> + </param> + + <param> + <name>Frozen Bit Values</name> + <key>frozen_bit_values</key> + <type>int_vector</type> + </param> +</block> diff --git a/gr-fec/grc/fec_polar_decoder_sc_list.xml b/gr-fec/grc/fec_polar_decoder_sc_list.xml new file mode 100644 index 0000000000..fa8208f141 --- /dev/null +++ b/gr-fec/grc/fec_polar_decoder_sc_list.xml @@ -0,0 +1,57 @@ +<?xml version="1.0"?> +<block> + <name>POLAR Decoder SC List Definition</name> + <key>variable_polar_decoder_sc_list_def</key> + <import>from gnuradio import fec</import> + <var_make> +self.$(id) = $(id) = fec.polar_decoder_sc_list.make($max_list_size, $block_size, $num_info_bits, $frozen_bit_positions, $frozen_bit_values, $is_packed) + </var_make> + <var_value>fec.polar_decoder_sc_list.make($max_list_size, $block_size, $num_info_bits, $frozen_bit_positions, $frozen_bit_values, $is_packed)</var_value> + <make></make> + + + <param> + <name>Packed Bits</name> + <key>is_packed</key> + <value>False</value> + <type>enum</type> + <option> + <name>No</name> + <key>False</key> + </option> + <option> + <name>Yes</name> + <key>True</key> + </option> + </param> + + <param> + <name>Maximum List Size (L)</name> + <key>max_list_size</key> + <type>int</type> + </param> + + <param> + <name>Block size (N)</name> + <key>block_size</key> + <type>int</type> + </param> + + <param> + <name>#Info Bits (K)</name> + <key>num_info_bits</key> + <type>int</type> + </param> + + <param> + <name>Frozen Bit Positions</name> + <key>frozen_bit_positions</key> + <type>int_vector</type> + </param> + + <param> + <name>Frozen Bit Values</name> + <key>frozen_bit_values</key> + <type>int_vector</type> + </param> +</block> diff --git a/gr-fec/include/gnuradio/fec/CMakeLists.txt b/gr-fec/include/gnuradio/fec/CMakeLists.txt index 0b3a5a36ab..10782250d7 100644 --- a/gr-fec/include/gnuradio/fec/CMakeLists.txt +++ b/gr-fec/include/gnuradio/fec/CMakeLists.txt @@ -47,6 +47,10 @@ install(FILES puncture_bb.h puncture_ff.h depuncture_bb.h - polar_encoder.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio/fec + polar_encoder.h + polar_decoder_sc.h + polar_common.h + polar_decoder_sc_list.h + polar_decoder_common.h DESTINATION ${GR_INCLUDE_DIR}/gnuradio/fec COMPONENT "fec_devel" ) diff --git a/gr-fec/include/gnuradio/fec/polar_common.h b/gr-fec/include/gnuradio/fec/polar_common.h new file mode 100644 index 0000000000..59e0ad38ba --- /dev/null +++ b/gr-fec/include/gnuradio/fec/polar_common.h @@ -0,0 +1,83 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_FEC_POLAR_COMMON_H +#define INCLUDED_FEC_POLAR_COMMON_H + +#include <gnuradio/fec/api.h> + +// Forward declaration for those objects. SWIG doesn't like them to be #include'd. +namespace gr { + namespace blocks { + namespace kernel { + class pack_k_bits; + class unpack_k_bits; + } + } +} + +namespace gr { + namespace fec { + + /*! + * \brief POLAR code common operations and attributes + * Erdal Arikan "Channel Polarization: A Method for Contructing Capacity-Achieving Codes for Symmetric Binary-Input Memoryless Channels", 2009 + */ + class FEC_API polar_common + { + public: + polar_common(int block_size, int num_info_bits, std::vector<int> frozen_bit_positions, std::vector<char> frozen_bit_values, bool is_packed = false); + ~polar_common(); + + protected: + const int block_size()const {return d_block_size;}; + const int block_power()const {return d_block_power;}; + const int num_info_bits() const {return d_num_info_bits;}; + const bool is_packed() const {return d_is_packed;}; + + // helper functions + long bit_reverse(long value, int active_bits) const; + void print_packed_bit_array(const unsigned char* printed_array, const int num_bytes) const; + void print_unpacked_bit_array(const unsigned char* bits, const unsigned int num_bytes) const; + const gr::blocks::kernel::unpack_k_bits* unpacker() const {return d_unpacker;}; + std::vector<int> info_bit_position_vector(); + + private: + int d_block_size; // depending on paper called 'N' or 'm' + int d_block_power; + int d_num_info_bits; // mostly abbreviated by 'K' + bool d_is_packed; + std::vector<int> d_frozen_bit_positions; + std::vector<int> d_info_bit_positions; + std::vector<char> d_frozen_bit_values; + void initialize_info_bit_position_vector(); + + gr::blocks::kernel::pack_k_bits *d_packer; + gr::blocks::kernel::unpack_k_bits *d_unpacker; + }; + + } // namespace fec +} // namespace gr + +#endif /* INCLUDED_FEC_POLAR_COMMON_H */ + diff --git a/gr-fec/include/gnuradio/fec/polar_decoder_common.h b/gr-fec/include/gnuradio/fec/polar_decoder_common.h new file mode 100644 index 0000000000..50003b6863 --- /dev/null +++ b/gr-fec/include/gnuradio/fec/polar_decoder_common.h @@ -0,0 +1,87 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_FEC_POLAR_DECODER_COMMON_H +#define INCLUDED_FEC_POLAR_DECODER_COMMON_H + +#include <gnuradio/fec/api.h> +#include <gnuradio/fec/generic_decoder.h> +#include <gnuradio/fec/polar_common.h> + +namespace gr { + namespace fec { + + /*! + * \brief Class holds common methods and attributes for different decoder implementations + * + */ + class FEC_API polar_decoder_common : public generic_decoder, public polar_common + { + public: + polar_decoder_common(int block_size, int num_info_bits, std::vector<int> frozen_bit_positions, std::vector<char> frozen_bit_values, bool is_packed); + ~polar_decoder_common(); + + // FECAPI + double rate(){return (1.0 * get_input_size() / get_output_size());}; + int get_input_size(){return block_size() / (is_packed() ? 8 : 1);}; + int get_output_size(){return num_info_bits() / (is_packed() ? 8 : 1);}; + bool set_frame_size(unsigned int frame_size){return false;}; + const char* get_output_conversion() {return "none";}; + + private: + const float D_LLR_FACTOR; + + protected: + // calculate LLRs for stage + float llr_odd(const float la, const float lb) const; + float llr_even(const float la, const float lb, const unsigned char f) const; + unsigned char llr_bit_decision(const float llr) const {return (llr < 0.0f) ? 1 : 0;}; + + // preparation for decoding + void initialize_llr_vector(float* llrs, const float* input); + // basic algorithm methods + void butterfly(float* llrs, const int stage, unsigned char* u, const int u_num); + void even_u_values(unsigned char* u_even, const unsigned char* u, const int u_num); + void odd_xor_even_values(unsigned char* u_xor, const unsigned char* u, const int u_num); + void demortonize_values(unsigned char* u); + + void extract_info_bits(unsigned char* output, const unsigned char* input) const; + + static void insert_bit_at_pos(unsigned char* u, const unsigned char ui, const unsigned int pos){u[pos >> 3] ^= ui << (7 - (pos % 8));}; + static unsigned char fetch_bit_at_pos(const unsigned char* u, const unsigned int pos){return (u[pos >> 3] >> (7 - (pos % 8))) & 0x01;}; + + // info shared among all implementations. + std::vector<int> d_frozen_bit_positions; + std::vector<int> d_info_bit_positions; + std::vector<char> d_frozen_bit_values; + + // helper functions. + void print_pretty_llr_vector(const float* llr_vec) const; + + }; + + } // namespace fec +} // namespace gr + +#endif /* INCLUDED_FEC_POLAR_DECODER_COMMON_H */ + diff --git a/gr-fec/include/gnuradio/fec/polar_decoder_sc.h b/gr-fec/include/gnuradio/fec/polar_decoder_sc.h new file mode 100644 index 0000000000..d9aa959fb9 --- /dev/null +++ b/gr-fec/include/gnuradio/fec/polar_decoder_sc.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_FEC_POLAR_DECODER_SC_H +#define INCLUDED_FEC_POLAR_DECODER_SC_H + +#include <gnuradio/fec/api.h> +#include <gnuradio/fec/polar_decoder_common.h> + + +namespace gr { + namespace fec { + + /*! + * \brief Standard successive cancellation decoder for POLAR codes + * It expects float input with bits mapped 1 --> -1, 0 --> 1 + * Or: f = 1.0 - 2.0 * bit + * + */ + class FEC_API polar_decoder_sc : public polar_decoder_common + { + public: + static generic_decoder::sptr make(int block_size, int num_info_bits, std::vector<int> frozen_bit_positions, std::vector<char> frozen_bit_values, bool is_packed = false); + ~polar_decoder_sc(); + + // FECAPI + void generic_work(void *in_buffer, void *out_buffer); + + private: + polar_decoder_sc(int block_size, int num_info_bits, std::vector<int> frozen_bit_positions, std::vector<char> frozen_bit_values, bool is_packed); + + unsigned int d_frozen_bit_counter; + + float* d_llr_vec; + unsigned char* d_u_hat_vec; + + unsigned char retrieve_bit_from_llr(float llr, const int pos); + void sc_decode(float* llrs, unsigned char* u); + }; + + } // namespace fec +} // namespace gr + +#endif /* INCLUDED_FEC_POLAR_DECODER_SC_H */ + diff --git a/gr-fec/include/gnuradio/fec/polar_decoder_sc_list.h b/gr-fec/include/gnuradio/fec/polar_decoder_sc_list.h new file mode 100644 index 0000000000..001ef66b1c --- /dev/null +++ b/gr-fec/include/gnuradio/fec/polar_decoder_sc_list.h @@ -0,0 +1,69 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + +#ifndef INCLUDED_POLAR_FEC_DECODER_SC_LIST_H +#define INCLUDED_POLAR_FEC_DECODER_SC_LIST_H + +#include <gnuradio/fec/api.h> +#include <gnuradio/fec/polar_decoder_common.h> + +namespace gr { + namespace fec { + namespace polar { + class scl_list; + class path; + } + + /*! + * \brief implements a successive cancellation list decoder for polar codes + * decoder is based on Tal, Vardy "List Decoding of Polar Codes", 2012 + * LLR version: Balatsoukas-Stimming, Parizi, Burg "LLR-based Successive Cancellation List Decoding of Polar Codes", 2015 + * + */ + class FEC_API polar_decoder_sc_list : public polar_decoder_common + { + public: + static generic_decoder::sptr make(int max_list_size, int block_size, int num_info_bits, std::vector<int> frozen_bit_positions, std::vector<char> frozen_bit_values, bool is_packed = false); + ~polar_decoder_sc_list(); + + // FECAPI + void generic_work(void *in_buffer, void *out_buffer); + + private: + polar_decoder_sc_list(int max_list_size, int block_size, int num_info_bits, std::vector<int> frozen_bit_positions, std::vector<char> frozen_bit_values, bool is_packed); + + unsigned int d_max_list_size; + polar::scl_list* d_scl; + unsigned int d_frozen_bit_counter; + + void decode_list(); + void calculate_next_llr_in_paths(int u_num); + void calculate_next_llr(polar::path* current_path, int u_num); + void update_with_frozenbit(const int u_num); + + }; + } // namespace fec +} // namespace gr + +#endif /* INCLUDED_POLAR_FEC_DECODER_SC_LIST_H */ + diff --git a/gr-fec/include/gnuradio/fec/polar_encoder.h b/gr-fec/include/gnuradio/fec/polar_encoder.h index 9cd37b8c39..85208bf49a 100644 --- a/gr-fec/include/gnuradio/fec/polar_encoder.h +++ b/gr-fec/include/gnuradio/fec/polar_encoder.h @@ -26,16 +26,7 @@ #include <gnuradio/fec/api.h> #include <gnuradio/fec/generic_encoder.h> - -// Forward declaration for those objects. SWIG doesn't like them to be #include'd. -namespace gr { - namespace blocks { - namespace kernel { - class pack_k_bits; - class unpack_k_bits; - } - } -} +#include <gnuradio/fec/polar_common.h> namespace gr { namespace fec { @@ -44,7 +35,7 @@ namespace gr { * \brief POLAR encoder * */ - class FEC_API polar_encoder : public generic_encoder + class FEC_API polar_encoder : public generic_encoder, public polar_common { public: static generic_encoder::sptr make(int block_size, int num_info_bits, std::vector<int> frozen_bit_positions, std::vector<char> frozen_bit_values, bool is_packed = false); @@ -53,17 +44,14 @@ namespace gr { // FECAPI void generic_work(void *in_buffer, void *out_buffer); double rate(){return (1.0 * get_input_size() / get_output_size());}; - int get_input_size(){return d_input_size;}; - int get_output_size(){return d_output_size;}; + int get_input_size(){return num_info_bits() / (is_packed() ? 8 : 1);}; + int get_output_size(){return block_size() / (is_packed() ? 8 : 1);}; bool set_frame_size(unsigned int frame_size){return false;}; + const char* get_input_conversion(){return is_packed() ? "pack" : "none";}; + const char* get_output_conversion(){return is_packed() ? "packed_bits" : "none";}; private: polar_encoder(int block_size, int num_info_bits, std::vector<int> frozen_bit_positions, std::vector<char> frozen_bit_values, bool is_packed); - int d_block_size; // depending on paper called 'N' or 'm' - int d_block_power; - int d_input_size, d_output_size; - bool d_is_packed; - int d_num_info_bits; // mostly abbreviated by 'K' std::vector<int> d_frozen_bit_positions; std::vector<int> d_info_bit_positions; std::vector<char> d_frozen_bit_values; @@ -90,13 +78,6 @@ namespace gr { void encode_packed_byte(unsigned char* target) const; void encode_vector_packed_interbyte(unsigned char* target) const; - // helper functions - long bit_reverse(long value, int active_bits) const; - void print_packed_bit_array(const unsigned char* printed_array, const int num_bytes) const; - - gr::blocks::kernel::pack_k_bits *d_packer; - gr::blocks::kernel::unpack_k_bits *d_unpacker; - }; } // namespace fec diff --git a/gr-fec/lib/CMakeLists.txt b/gr-fec/lib/CMakeLists.txt index 00cb061d4e..0343ce3cfc 100644 --- a/gr-fec/lib/CMakeLists.txt +++ b/gr-fec/lib/CMakeLists.txt @@ -81,7 +81,12 @@ list(APPEND gnuradio_fec_sources tpc_common.cc tpc_decoder.cc tpc_encoder.cc - polar_encoder.cc + polar_encoder.cc + polar_decoder_sc.cc + polar_common.cc + polar_decoder_sc_list.cc + polar_decoder_common.cc + scl_list.cc ) #Add Windows DLL resource file if using MSVC diff --git a/gr-fec/lib/polar_common.cc b/gr-fec/lib/polar_common.cc new file mode 100644 index 0000000000..c76f5301a5 --- /dev/null +++ b/gr-fec/lib/polar_common.cc @@ -0,0 +1,139 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/io_signature.h> +#include <gnuradio/fec/polar_common.h> + +#include <gnuradio/blocks/pack_k_bits.h> +#include <gnuradio/blocks/unpack_k_bits.h> + +#include <cmath> +#include <stdexcept> +#include <iostream> +#include <vector> + +namespace gr +{ + namespace fec + { + + polar_common::polar_common(int block_size, int num_info_bits, + std::vector<int> frozen_bit_positions, + std::vector<char> frozen_bit_values, bool is_packed) : + d_block_size(block_size), d_block_power((int) log2(float(block_size))), d_num_info_bits(num_info_bits), d_is_packed(is_packed), + d_frozen_bit_positions(frozen_bit_positions), d_frozen_bit_values(frozen_bit_values) + { + if(pow(2, d_block_power) != d_block_size) { + throw std::runtime_error("block_size MUST be a power of 2!"); + } + + unsigned int num_frozen_bits = d_block_size - d_num_info_bits; + if(num_frozen_bits != d_frozen_bit_positions.size()) { + throw std::runtime_error( + "number of frozen bit positions must equal block_size - num_info_bits"); + } + + // According to papers frozen bits default to '0'. + while(d_frozen_bit_values.size() < num_frozen_bits) { + d_frozen_bit_values.push_back(0); + } + initialize_info_bit_position_vector(); + + d_packer = new gr::blocks::kernel::pack_k_bits(8); + d_unpacker = new gr::blocks::kernel::unpack_k_bits(8); + } + + + std::vector<int> + polar_common::info_bit_position_vector() + { + return d_info_bit_positions; + } + + void + polar_common::initialize_info_bit_position_vector() + { + int num_frozen_bit = 0; + for(int i = 0; i < block_size(); i++) { + int frozen_pos = d_frozen_bit_positions.at(num_frozen_bit); + if(i != frozen_pos) { + d_info_bit_positions.push_back((int) i); + } + else { + num_frozen_bit++; + num_frozen_bit = std::min(num_frozen_bit, (int) (d_frozen_bit_positions.size() - 1)); + } + } + } + + polar_common::~polar_common() + { + delete d_packer; + delete d_unpacker; + } + + long + polar_common::bit_reverse(long value, int active_bits) const + { + long r = 0; + for(int i = 0; i < active_bits; i++) { + r <<= 1; + r |= value & 1; + value >>= 1; + } + return r; + } + + void + polar_common::print_packed_bit_array(const unsigned char* printed_array, + const int num_bytes) const + { + int num_bits = num_bytes << 3; + unsigned char* temp = new unsigned char[num_bits]; + unpacker()->unpack(temp, printed_array, num_bytes); + + std::cout << "["; + for(int i = 0; i < num_bits; i++) { + std::cout << (int) *(temp + i) << " "; + } + std::cout << "]" << std::endl; + + delete [] temp; + } + + void + polar_common::print_unpacked_bit_array(const unsigned char* bits, + const unsigned int num_bytes) const + { + std::cout << "( "; + for(unsigned int i = 0; i < num_bytes; i++){ + std::cout << (int) *bits++ << ", "; + } + std::cout << ")" << std::endl; + } + + } /* namespace fec */ +} /* namespace gr */ diff --git a/gr-fec/lib/polar_decoder_common.cc b/gr-fec/lib/polar_decoder_common.cc new file mode 100644 index 0000000000..028564101f --- /dev/null +++ b/gr-fec/lib/polar_decoder_common.cc @@ -0,0 +1,209 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/io_signature.h> +#include <gnuradio/fec/polar_decoder_common.h> +#include <volk/volk.h> + +#include <cstdio> + +#define INT_BIT_MASK 0x80000000 + +namespace gr { + namespace fec { + + polar_decoder_common::polar_decoder_common(int block_size, int num_info_bits, + std::vector<int> frozen_bit_positions, + std::vector<char> frozen_bit_values, bool is_packed) : + polar_common(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, is_packed), + D_LLR_FACTOR(2.19722458f), + d_frozen_bit_positions(frozen_bit_positions), + d_frozen_bit_values(frozen_bit_values) + { + } + + polar_decoder_common::~polar_decoder_common() + { + } + + void + polar_decoder_common::initialize_llr_vector(float* llrs, const float* input) + { + volk_32f_s32f_multiply_32f(llrs + block_size() * block_power(), input, D_LLR_FACTOR, block_size()); + } + + float + polar_decoder_common::llr_odd(const float la, const float lb) const + { + return copysignf(1.0f, la) * copysignf(1.0f, lb) * std::min(fabs(la), fabs(lb)); + } + + float + polar_decoder_common::llr_even(const float la, const float lb, const unsigned char f) const + { + switch(f){ + case 0: + return lb + la; + default: + return lb - la; + } + } + + void + polar_decoder_common::butterfly(float* llrs, const int stage, unsigned char* u, const int u_num) + { +// if(!(block_power() > stage)){ +// return; +// } + const int next_stage = stage + 1; + const int stage_half_block_size = block_size() >> next_stage; + +// // this is a natural bit order impl + float* next_llrs = llrs + block_size(); // LLRs are stored in an consecutive array. + float* call_row_llr = llrs + u_num; + const int upper_right = u_num >> 1; // floor divide by 2. + const float* upper_right_llr_ptr = next_llrs + upper_right; + const float* lower_right_llr_ptr = upper_right_llr_ptr + stage_half_block_size; + + if(u_num % 2){ + const unsigned char f = u[u_num - 1]; +// const unsigned char f = fetch_bit_at_pos(u, u_num - 1); + *call_row_llr = llr_even(*upper_right_llr_ptr, *lower_right_llr_ptr, f); + return; + } + + if(block_power() > next_stage) { + unsigned char* u_half = u + block_size(); + odd_xor_even_values(u_half, u, u_num); + butterfly(next_llrs, next_stage, u_half, upper_right); + + even_u_values(u_half, u, u_num); + butterfly(next_llrs + stage_half_block_size, next_stage, u_half, upper_right); + } + + *call_row_llr = llr_odd(*upper_right_llr_ptr, *lower_right_llr_ptr); + } + + + void + polar_decoder_common::even_u_values(unsigned char* u_even, const unsigned char* u, + const int u_num) + { + u++; + for(int i = 1; i < u_num; i += 2){ + *u_even++ = *u; + u += 2; + } + +// short* target = (short*) u_even; +// short* src = (short*) u; +// +// const int iterations = std::max(1, u_num >> 3); +// for(int i = 0; i < iterations; i++){ +// *target = *src << 1; +// demortonize_values((unsigned char*) target); +// u_even++; +// target = (short*) u_even; +// src++; +// } + } + + void + polar_decoder_common::odd_xor_even_values(unsigned char* u_xor, const unsigned char* u, + const int u_num) + { + for(int i = 1; i < u_num; i += 2){ + *u_xor++ = *u ^ *(u + 1); + u += 2; + } + +// short* target = (short*) u_xor; +// short* src = (short*) u; +// +// const int iterations = std::max(1, u_num >> 3); +// for(int i = 0; i < iterations; i++){ +// *target = *src ^ (*src << 1); +// demortonize_values((unsigned char*) target); +// u_xor++; +// target = (short*) u_xor; +// src++; +// } + } + + void + polar_decoder_common::extract_info_bits(unsigned char* output, const unsigned char* input) const + { + unsigned int frozenbit_num = 0; + for(int i = 0; i < block_size(); i++){ + if(frozenbit_num < d_frozen_bit_positions.size() && d_frozen_bit_positions.at(frozenbit_num) == i){ + frozenbit_num++; + } + else{ + *output++ = *input; + } + input++; + } + +// unsigned int frozenbit_num = 0; +// for(int i = 0; i < block_size(); i++){ +// if(frozenbit_num < d_frozen_bit_positions.size() && d_frozen_bit_positions.at(frozenbit_num) == i){ +// frozenbit_num++; +// } +// else{ +// *output++ = fetch_bit_at_pos(input, i); // *input; +// } +// } + } + + void + polar_decoder_common::demortonize_values(unsigned char* u) + { + *u &= 0xaa; // b0d0f0h0 + *u = (*u ^ (*u << 1)) & 0xcc; // bd00fh00 + *u = (*u ^ (*u << 2)) & 0xf0; // bdfh0000 + + unsigned char* u2 = u + 1; + *u2 &= 0xaa; // b0d0f0h0 + *u2 = (*u2 ^ (*u2 << 1)) & 0xcc; // bd00fh00 + *u2 = (*u2 ^ (*u2 << 2)) & 0xf0; // bdfh0000 + *u ^= (*u2 >> 4); + } + + void + polar_decoder_common::print_pretty_llr_vector(const float* llr_vec) const + { + for(int row = 0; row < block_size(); row++) { + std::cout << row << "->" << int(bit_reverse(row, block_power())) << ":\t"; + for(int stage = 0; stage < block_power() + 1; stage++) { + printf("%+4.2f, ", llr_vec[(stage * block_size()) + row]); + } + std::cout << std::endl; + } + } + + } /* namespace fec */ +} /* namespace gr */ + diff --git a/gr-fec/lib/polar_decoder_sc.cc b/gr-fec/lib/polar_decoder_sc.cc new file mode 100644 index 0000000000..e4f64b5e99 --- /dev/null +++ b/gr-fec/lib/polar_decoder_sc.cc @@ -0,0 +1,99 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/io_signature.h> +#include <gnuradio/fec/polar_decoder_sc.h> +#include <volk/volk.h> + +#include <cmath> +#include <cstdio> + +namespace gr +{ + namespace fec + { + + generic_decoder::sptr + polar_decoder_sc::make(int block_size, int num_info_bits, std::vector<int> frozen_bit_positions, + std::vector<char> frozen_bit_values, bool is_packed) + { + return generic_decoder::sptr( + new polar_decoder_sc(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, + is_packed)); + } + + polar_decoder_sc::polar_decoder_sc(int block_size, int num_info_bits, + std::vector<int> frozen_bit_positions, + std::vector<char> frozen_bit_values, bool is_packed) : + polar_decoder_common(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, is_packed), + d_frozen_bit_counter(0) + { + d_llr_vec = (float*) volk_malloc(sizeof(float) * block_size * (block_power() + 1), volk_get_alignment()); + memset(d_llr_vec, 0, sizeof(float) * block_size * (block_power() + 1)); + d_u_hat_vec = (unsigned char*) volk_malloc(block_size * (block_power() + 1), volk_get_alignment()); + memset(d_u_hat_vec, 0, sizeof(unsigned char) * block_size * (block_power() + 1)); + } + + polar_decoder_sc::~polar_decoder_sc() + { + volk_free(d_llr_vec); + volk_free(d_u_hat_vec); + } + + void + polar_decoder_sc::generic_work(void* in_buffer, void* out_buffer) + { + const float *in = (const float*) in_buffer; + unsigned char *out = (unsigned char*) out_buffer; + + initialize_llr_vector(d_llr_vec, in); + sc_decode(d_llr_vec, d_u_hat_vec); + extract_info_bits(out, d_u_hat_vec); + } + + void + polar_decoder_sc::sc_decode(float* llrs, unsigned char* u) + { + d_frozen_bit_counter = 0; + memset(u, 0, sizeof(unsigned char) * block_size() * block_power()); + for(int i = 0; i < block_size(); i++){ + butterfly(llrs, 0, u, i); + u[i] = retrieve_bit_from_llr(llrs[i], i); +// const unsigned char bit = retrieve_bit_from_llr(llrs[i], i); +// insert_bit_at_pos(u, bit, i); + } + } + + unsigned char + polar_decoder_sc::retrieve_bit_from_llr(float llr, const int pos) + { + if(d_frozen_bit_counter < d_frozen_bit_positions.size() && pos == d_frozen_bit_positions.at(d_frozen_bit_counter)){ + return d_frozen_bit_values.at(d_frozen_bit_counter++); + } + return llr_bit_decision(llr); + } + } /* namespace fec */ +} /* namespace gr */ diff --git a/gr-fec/lib/polar_decoder_sc_list.cc b/gr-fec/lib/polar_decoder_sc_list.cc new file mode 100644 index 0000000000..9340e305d3 --- /dev/null +++ b/gr-fec/lib/polar_decoder_sc_list.cc @@ -0,0 +1,123 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/io_signature.h> +#include <gnuradio/fec/polar_decoder_sc_list.h> +#include <volk/volk.h> +#include <scl_list.h> + +#include <cmath> +#include <algorithm> + +namespace gr +{ + namespace fec + { + + generic_decoder::sptr + polar_decoder_sc_list::make(int max_list_size, int block_size, int num_info_bits, + std::vector<int> frozen_bit_positions, + std::vector<char> frozen_bit_values, bool is_packed) + { + return generic_decoder::sptr( + new polar_decoder_sc_list(max_list_size, block_size, num_info_bits, frozen_bit_positions, + frozen_bit_values, is_packed)); + } + + polar_decoder_sc_list::polar_decoder_sc_list(int max_list_size, int block_size, + int num_info_bits, + std::vector<int> frozen_bit_positions, + std::vector<char> frozen_bit_values, + bool is_packed) : + polar_decoder_common(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, + is_packed), d_max_list_size(max_list_size), d_frozen_bit_counter(0) + { + d_scl = new polar::scl_list(max_list_size, block_size, block_power()); + } + + polar_decoder_sc_list::~polar_decoder_sc_list() + { + delete d_scl; + } + + void + polar_decoder_sc_list::generic_work(void* in_buffer, void* out_buffer) + { + const float *in = (const float*) in_buffer; + unsigned char *out = (unsigned char*) out_buffer; + polar::path* init_path = d_scl->initial_path(); + initialize_llr_vector(init_path->llr_vec, in); + memset(init_path->u_vec, 0, sizeof(unsigned char) * block_size() * (block_power() + 1)); + decode_list(); + const polar::path* temp = d_scl->optimal_path(); + extract_info_bits(out, temp->u_vec); + } + + void + polar_decoder_sc_list::decode_list() + { + d_frozen_bit_counter = 0; + for(int i = 0; i < block_size(); i++){ + calculate_next_llr_in_paths(i); + } + + } + + void + polar_decoder_sc_list::calculate_next_llr_in_paths(int u_num) + { + for(unsigned int i = 0; i < d_scl->active_size(); i++){ + polar::path* current_path = d_scl->next_active_path(); + calculate_next_llr(current_path, u_num); + } + + // 1. if frozen bit, update with known value + if(d_frozen_bit_counter < d_frozen_bit_positions.size() && u_num == d_frozen_bit_positions.at(d_frozen_bit_counter)){ + update_with_frozenbit(u_num); + } + // 2. info bit + else{ + d_scl->set_info_bit(u_num); + } + } + + void + polar_decoder_sc_list::update_with_frozenbit(const int u_num) + { + unsigned char frozen_bit = d_frozen_bit_values[d_frozen_bit_counter]; + d_scl->set_frozen_bit(frozen_bit, u_num); + d_frozen_bit_counter++; + } + + void + polar_decoder_sc_list::calculate_next_llr(polar::path* current_path, int u_num) + { + butterfly(current_path->llr_vec, 0, current_path->u_vec, u_num); + } + } /* namespace fec */ +} /* namespace gr */ + + diff --git a/gr-fec/lib/polar_encoder.cc b/gr-fec/lib/polar_encoder.cc index 1214e803a7..7187ea6120 100644 --- a/gr-fec/lib/polar_encoder.cc +++ b/gr-fec/lib/polar_encoder.cc @@ -33,83 +33,63 @@ #include <gnuradio/blocks/pack_k_bits.h> #include <gnuradio/blocks/unpack_k_bits.h> -namespace gr { - namespace fec { +namespace gr +{ + namespace fec + { generic_encoder::sptr polar_encoder::make(int block_size, int num_info_bits, std::vector<int> frozen_bit_positions, std::vector<char> frozen_bit_values, bool is_packed) { - return generic_encoder::sptr(new polar_encoder(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, is_packed)); + return generic_encoder::sptr( + new polar_encoder(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, + is_packed)); } - polar_encoder::polar_encoder(int block_size, int num_info_bits, std::vector<int> frozen_bit_positions, std::vector<char> frozen_bit_values, bool is_packed): - d_block_size(block_size), - d_input_size(num_info_bits / (is_packed ? 8 : 1)), - d_output_size(block_size / (is_packed ? 8 : 1)), - d_is_packed(is_packed), - d_num_info_bits(num_info_bits), - d_frozen_bit_positions(frozen_bit_positions), - d_frozen_bit_values(frozen_bit_values) + polar_encoder::polar_encoder(int block_size, int num_info_bits, + std::vector<int> frozen_bit_positions, + std::vector<char> frozen_bit_values, bool is_packed) : + polar_common(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, is_packed), + d_frozen_bit_positions(frozen_bit_positions), + d_frozen_bit_values(frozen_bit_values) { - int n = (int) log2(float(block_size)); - d_block_power = n; - if(pow(2, n) != block_size){ - throw std::runtime_error("block_size MUST be a power of 2!"); - } - - unsigned int num_frozen_bits = d_block_size - d_num_info_bits; - if(num_frozen_bits != d_frozen_bit_positions.size()){ - throw std::runtime_error("number of frozen bit positions must equal block_size - num_info_bits"); - } + unsigned int num_frozen_bits = block_size - num_info_bits; - while(d_frozen_bit_values.size() < num_frozen_bits){ + while(d_frozen_bit_values.size() < num_frozen_bits) { d_frozen_bit_values.push_back(0); } - int k = 8; - d_unpacker = new gr::blocks::kernel::unpack_k_bits(k); - d_packer = new gr::blocks::kernel::pack_k_bits(k); - setup_frozen_bit_inserter(); } void polar_encoder::setup_frozen_bit_inserter() { - d_block_array = (unsigned char*) volk_malloc(d_block_size >> 3, volk_get_alignment()); - d_frozen_bit_prototype = (unsigned char*) volk_malloc(d_block_size >> 3, volk_get_alignment()); - memset(d_frozen_bit_prototype, 0, d_block_size >> 3); + d_block_array = (unsigned char*) volk_malloc(block_size() >> 3, volk_get_alignment()); + d_frozen_bit_prototype = (unsigned char*) volk_malloc(block_size() >> 3, + volk_get_alignment()); + memset(d_frozen_bit_prototype, 0, block_size() >> 3); - for(unsigned int i = 0; i < d_frozen_bit_positions.size(); i++){ - int rev_pos = (int) bit_reverse((long) d_frozen_bit_positions.at(i), d_block_power); + for(unsigned int i = 0; i < d_frozen_bit_positions.size(); i++) { + int rev_pos = (int) bit_reverse((long) d_frozen_bit_positions.at(i), block_power()); unsigned char frozen_bit = (unsigned char) d_frozen_bit_values.at(i); - insert_unpacked_bit_into_packed_array_at_position(d_frozen_bit_prototype, frozen_bit, rev_pos); + insert_unpacked_bit_into_packed_array_at_position(d_frozen_bit_prototype, frozen_bit, + rev_pos); } -// print_packed_bit_array(d_frozen_bit_prototype, d_block_size >> 3); - - int num_frozen_bit = 0; - for(int i = 0; i < d_block_size; i++){ - int frozen_pos = d_frozen_bit_positions.at(num_frozen_bit); - if(i != frozen_pos){ - d_info_bit_positions.push_back((int) bit_reverse((long) i, d_block_power)); - } - else{ - num_frozen_bit++; - num_frozen_bit = std::min(num_frozen_bit, (int) (d_frozen_bit_positions.size() - 1)); - } + std::vector<int> temp_vec = info_bit_position_vector(); + for(unsigned int i = 0; i < temp_vec.size(); i++){ + d_info_bit_positions.push_back((int) bit_reverse((long) temp_vec.at(i), block_power())); } - if((int) d_info_bit_positions.size() != d_num_info_bits){ + + if((int) d_info_bit_positions.size() != num_info_bits()) { throw std::runtime_error("number of info bit positions MUST equal num_info_bits (K)!"); } } polar_encoder::~polar_encoder() { - delete d_unpacker; - delete d_packer; - volk_free(d_block_array); volk_free(d_frozen_bit_prototype); } @@ -120,14 +100,14 @@ namespace gr { const unsigned char *in = (const unsigned char*) in_buffer; unsigned char *out = (unsigned char*) out_buffer; - if(d_is_packed){ + if(is_packed()) { insert_packed_frozen_bits_and_reverse(out, in); encode_vector_packed(out); } - else{ + else { insert_unpacked_frozen_bits_and_reverse(d_block_array, in); encode_vector_packed(d_block_array); - d_unpacker->unpack(out, d_block_array, d_block_size >> 3); + unpacker()->unpack(out, d_block_array, block_size() >> 3); } // insert_frozen_bits(d_block_array, in); @@ -145,8 +125,8 @@ namespace gr { void polar_encoder::encode_vector_packed_subbyte(unsigned char* target) const { - int num_bytes_per_block = d_block_size >> 3; - while(num_bytes_per_block){ + int num_bytes_per_block = block_size() >> 3; + while(num_bytes_per_block) { encode_packed_byte(target); ++target; --num_bytes_per_block; @@ -168,15 +148,15 @@ namespace gr { { int branch_byte_size = 1; unsigned char* pos; - int n_branches = d_block_size >> 4; + int n_branches = block_size() >> 4; int byte = 0; - for(int stage = 3; stage < d_block_power; ++stage){ + for(int stage = 3; stage < block_power(); ++stage) { pos = target; - for(int branch = 0; branch < n_branches; ++branch){ + for(int branch = 0; branch < n_branches; ++branch) { byte = 0; - while(byte < branch_byte_size){ + while(byte < branch_byte_size) { *pos ^= *(pos + branch_byte_size); ++pos; ++byte; @@ -194,12 +174,13 @@ namespace gr { polar_encoder::insert_unpacked_frozen_bits_and_reverse(unsigned char* target, const unsigned char* input) const { - memcpy(target, d_frozen_bit_prototype, d_block_size >> 3); + memcpy(target, d_frozen_bit_prototype, block_size() >> 3); const int* info_bit_positions_ptr = &d_info_bit_positions[0]; - const unsigned char* end_input = input + d_num_info_bits; + const unsigned char* end_input = input + num_info_bits(); int bit_pos = 7; - while(input < end_input){ - insert_packet_bit_into_packed_array_at_position(target, *input++, *info_bit_positions_ptr++, bit_pos); + while(input < end_input) { + insert_packet_bit_into_packed_array_at_position(target, *input++, *info_bit_positions_ptr++, + bit_pos); } } @@ -207,16 +188,16 @@ namespace gr { polar_encoder::insert_packed_frozen_bits_and_reverse(unsigned char* target, const unsigned char* input) const { - memcpy(target, d_frozen_bit_prototype, d_block_size >> 3); + memcpy(target, d_frozen_bit_prototype, block_size() >> 3); const int* info_bit_positions_ptr = &d_info_bit_positions[0]; int bit_num = 0; unsigned char byte = *input; int bit_pos; - while(bit_num < d_num_info_bits){ + while(bit_num < num_info_bits()) { bit_pos = *info_bit_positions_ptr++; insert_packet_bit_into_packed_array_at_position(target, byte, bit_pos, bit_num % 8); ++bit_num; - if(bit_num % 8 == 0){ + if(bit_num % 8 == 0) { ++input; byte = *input; } @@ -239,38 +220,22 @@ namespace gr { const int target_pos, const int bit_pos) const { - insert_unpacked_bit_into_packed_array_at_position(target, (bit >> (7 - bit_pos)) & 0x01, target_pos); - } - - void - polar_encoder::print_packed_bit_array(const unsigned char* printed_array, const int num_bytes) const - { - int num_bits = num_bytes << 3; - unsigned char* temp = (unsigned char*) volk_malloc(num_bits, volk_get_alignment()); - d_unpacker->unpack(temp, printed_array, num_bytes); - - - std::cout << "["; - for(int i = 0; i < num_bits; i++){ - std::cout << (int) *(temp + i) << " "; - } - std::cout << "]" << std::endl; - - volk_free(temp); + insert_unpacked_bit_into_packed_array_at_position(target, (bit >> (7 - bit_pos)) & 0x01, + target_pos); } void polar_encoder::insert_frozen_bits(unsigned char* target, const unsigned char* input) { int frozen_num = 0; - int num_frozen_bits = d_block_size - d_num_info_bits; + int num_frozen_bits = block_size() - num_info_bits(); int info_num = 0; - for(int i = 0; i < d_block_size; i++){ - if(frozen_num < num_frozen_bits && d_frozen_bit_positions.at(frozen_num) == i){ + for(int i = 0; i < block_size(); i++) { + if(frozen_num < num_frozen_bits && d_frozen_bit_positions.at(frozen_num) == i) { target[i] = d_frozen_bit_values.at(frozen_num); frozen_num++; } - else{ + else { target[i] = input[info_num]; info_num++; } @@ -280,19 +245,19 @@ namespace gr { void polar_encoder::bit_reverse_vector(unsigned char* target, const unsigned char* input) { - for(int i = 0; i < d_block_size; i++){ - target[bit_reverse(long(i), d_block_power)] = input[i]; + for(int i = 0; i < block_size(); i++) { + target[bit_reverse(long(i), block_power())] = input[i]; } } void polar_encoder::encode_vector(unsigned char* target) { - for(int stage = 0; stage < d_block_power; stage++){ + for(int stage = 0; stage < block_power(); stage++) { int n_branches = pow(2, stage); - int branch_elements = d_block_size / (2 * n_branches); - for(int branch = 0; branch < n_branches; branch++){ - for(int e = 0; e < branch_elements; e++){ + int branch_elements = block_size() / (2 * n_branches); + for(int branch = 0; branch < n_branches; branch++) { + for(int e = 0; e < branch_elements; e++) { int pos = branch * branch_elements * 2 + e; target[pos] ^= target[pos + branch_elements]; } @@ -300,19 +265,6 @@ namespace gr { } } - long - polar_encoder::bit_reverse(long value, int active_bits) const - { - long r = 0; - for(int i = 0; i < active_bits; i++){ - r <<= 1; - r |= value & 1; - value >>= 1; - } - return r; - } - } /* namespace fec */ } /* namespace gr */ - diff --git a/gr-fec/lib/scl_list.cc b/gr-fec/lib/scl_list.cc new file mode 100644 index 0000000000..6942bfb275 --- /dev/null +++ b/gr-fec/lib/scl_list.cc @@ -0,0 +1,191 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include <scl_list.h> +#include <cstring> +#include <iostream> +#include <algorithm> +#include <volk/volk.h> + +namespace gr { + namespace fec { + namespace polar { + + scl_list::scl_list(const unsigned int size, const unsigned int block_size, const unsigned int block_power): + d_list_size(size), d_block_size(block_size), d_block_power(block_power), d_num_buff_elements(block_size * (block_power + 1)) + { + for(unsigned int i = 0; i < 2 * size; i++){ + d_path_list.push_back(new path()); + } + + for(unsigned int i = 0; i < size; i++){ + d_path_list[i]->llr_vec = (float*) volk_malloc(sizeof(float) * d_num_buff_elements, volk_get_alignment()); + memset(d_path_list[i]->llr_vec, 0, sizeof(float) * d_num_buff_elements); + d_path_list[i]->u_vec = (unsigned char*) volk_malloc(sizeof(unsigned char) * d_num_buff_elements, volk_get_alignment()); + memset(d_path_list[i]->u_vec, 0, sizeof(unsigned char) * d_num_buff_elements); + d_path_list[i]->owns_vectors = true; + } + + d_path_list[0]->is_active = true; + d_active_path_counter = 1; + d_active_pos = 0; + } + + scl_list::~scl_list() + { + for(unsigned int i = 0; i < d_path_list.size(); i++){ + delete d_path_list[i]; + } + } + + + const path* + scl_list::optimal_path() + { + const path* temp = *std::min_element(d_path_list.begin(), d_path_list.begin() + d_active_path_counter, path_compare); + reset(); + return temp; + } + + void + scl_list::reset() + { + // leave 0th element active for next iteration + d_path_list[0]->path_metric = 0.0f; + for(unsigned int i = 1; i < d_path_list.size(); i++){ + d_path_list[i]->is_active = false; + d_path_list[i]->path_metric = 0.0f; + } + d_active_path_counter = 1; + d_active_pos = 0; + } + + void + scl_list::set_info_bit(const int bit_pos) + { + if(d_active_path_counter < d_list_size) { + const int offset = d_active_path_counter; + for(int i = 0; i < offset; i++) { + duplicate_path(d_path_list[i + offset], d_path_list[i]); + d_path_list[i]->path_metric = update_path_metric(d_path_list[i]->path_metric, + d_path_list[i]->llr_vec[bit_pos], 0); + d_path_list[i + offset]->path_metric = update_path_metric( + d_path_list[i + offset]->path_metric, d_path_list[i + offset]->llr_vec[bit_pos], 1); + d_path_list[i]->u_vec[bit_pos] = 0; +// insert_bit_at_pos(d_path_list[i]->u_vec, 0, bit_pos); + d_path_list[i + offset]->u_vec[bit_pos] = 1; +// insert_bit_at_pos(d_path_list[i + offset]->u_vec, 1, bit_pos); + } + } + else { + + for(unsigned int i = 0; i < d_list_size; i++) { + branch_paths(d_path_list[i + d_list_size], d_path_list[i], d_path_list[i]->llr_vec[bit_pos]); + } + std::sort(d_path_list.begin(), d_path_list.end(), path_compare); + + for(unsigned int i = 0; i < d_list_size; i++) { + if(!d_path_list[i]->owns_vectors) { + int t_pos = d_list_size; + while(!d_path_list[t_pos]->owns_vectors) { + t_pos++; + } + steal_vector_ownership(d_path_list[i], d_path_list[t_pos]); + d_path_list[i]->u_vec[bit_pos] = 1; +// insert_bit_at_pos(d_path_list[i]->u_vec, 1, bit_pos); + } + else{ + d_path_list[i]->u_vec[bit_pos] = 0; +// insert_bit_at_pos(d_path_list[i]->u_vec, 0, bit_pos); + } + } + } + d_active_pos = 0; + } + + void + scl_list::branch_paths(path* target, path* original, const float llr) + { + target->path_metric = update_path_metric(original->path_metric, llr, 1); + original->path_metric = update_path_metric(original->path_metric, llr, 0); + target->llr_vec = original->llr_vec; + target->u_vec = original->u_vec; + } + + void + scl_list::steal_vector_ownership(path* target, path* original) + { + memcpy(original->llr_vec, target->llr_vec, sizeof(float) * d_num_buff_elements); + memcpy(original->u_vec, target->u_vec, sizeof(unsigned char) * d_num_buff_elements); + target->llr_vec = original->llr_vec; + target->u_vec = original->u_vec; + target->owns_vectors = true; + original->owns_vectors = false; + } + + void + scl_list::duplicate_path(path* target, const path* original) + { + memcpy(target->llr_vec, original->llr_vec, sizeof(float) * d_num_buff_elements); + memcpy(target->u_vec, original->u_vec, sizeof(unsigned char) * d_num_buff_elements); + target->path_metric = original->path_metric; + d_active_path_counter++; + target->is_active = true; + } + + float + scl_list::update_path_metric(const float last_pm, const float llr, + const float ui) const + { + if((ui == 0 && llr > 0.0f) || (ui == 1 && llr < 0.0f)){ +// if(ui == (unsigned char) (0.5 * 1 - copysignf(1.0f, llr))){ + return last_pm; + } + return last_pm + fabs(llr); + } + + void + scl_list::set_frozen_bit(const unsigned char frozen_bit, const int bit_pos) + { + for(unsigned int i = 0; i < d_active_path_counter; i++){ +// insert_bit_at_pos(d_path_list[i]->u_vec, frozen_bit, bit_pos); + d_path_list[i]->u_vec[bit_pos] = frozen_bit; + d_path_list[i]->path_metric = update_path_metric(d_path_list[i]->path_metric, d_path_list[i]->llr_vec[bit_pos], frozen_bit); + } + d_active_pos = 0; + } + + path::path(): + path_metric(0.0f), owns_vectors(false), is_active(false), llr_vec(NULL), u_vec(NULL) + { + } + + path::~path(){ + if(owns_vectors){ + volk_free(llr_vec); + volk_free(u_vec); + } + } + + } /* namespace polar */ + } /* namespace fec */ +} /* namespace gr */ diff --git a/gr-fec/lib/scl_list.h b/gr-fec/lib/scl_list.h new file mode 100644 index 0000000000..8f09198157 --- /dev/null +++ b/gr-fec/lib/scl_list.h @@ -0,0 +1,83 @@ +/* -*- c++ -*- */ +/* + * Copyright 2015 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_FEC_SCL_LIST_H +#define INCLUDED_FEC_SCL_LIST_H + +#include <vector> + +namespace gr { + namespace fec { + namespace polar { + struct path { + path(); + ~path(); + float path_metric; + bool owns_vectors; + bool is_active; + float* llr_vec; + unsigned char* u_vec; + }; + + /*! + * \brief List implementation for Successive Cancellation List decoders + * + */ + class scl_list{ + const unsigned int d_list_size; + const unsigned int d_block_size; + const unsigned int d_block_power; + const unsigned int d_num_buff_elements; + std::vector<path*> d_path_list; + unsigned int d_active_path_counter; + unsigned int d_active_pos; + + float update_path_metric(const float last_pm, const float llr, const float ui) const; + void duplicate_path(path* target, const path* original); + void branch_paths(path* target, path* original, const float llr); + void steal_vector_ownership(path* target, path* original); + + static void insert_bit_at_pos(unsigned char* u, const unsigned char ui, const unsigned int pos){u[pos >> 3] ^= ui << (7 - (pos % 8));}; + + // comparator for std::sort + static bool path_compare(path* first, path* second){return first->path_metric < second->path_metric;}; + + public: + scl_list(const unsigned int list_size, const unsigned int block_size, const unsigned int block_power); + virtual + ~scl_list(); + const unsigned int size() const {return d_list_size;}; + const unsigned int active_size() const {return d_active_path_counter;}; + + path* initial_path() const {return d_path_list[0];}; + path* next_active_path(){return d_path_list[d_active_pos++];}; + void set_frozen_bit(const unsigned char frozen_bit, const int bit_pos); + void set_info_bit(const int bit_pos); + const path* optimal_path(); + void reset(); + }; + + } /* namespace polar */ + } /* namespace fec */ +} /* namespace gr */ + +#endif /* INCLUDED_FEC_SCL_LIST_H */ diff --git a/gr-fec/python/fec/polar/channel_construction_bec.py b/gr-fec/python/fec/polar/channel_construction_bec.py index cd61f463f6..4d3654d010 100644 --- a/gr-fec/python/fec/polar/channel_construction_bec.py +++ b/gr-fec/python/fec/polar/channel_construction_bec.py @@ -87,6 +87,12 @@ def get_frozen_bit_indices_from_capacities(chan_caps, nfrozen): return np.sort(indexes) +def get_bec_frozen_indices(nblock, kfrozen, eta): + bec_caps = calculate_bec_channel_capacities(eta, nblock) + positions = get_frozen_bit_indices_from_capacities(bec_caps, kfrozen) + return positions + + def bec_channel_contruction_tests(): n = 2 ** 10 k = n // 2 diff --git a/gr-fec/python/fec/polar/channel_construction_bsc.py b/gr-fec/python/fec/polar/channel_construction_bsc.py index 8cee7ceac5..2263bf0091 100755 --- a/gr-fec/python/fec/polar/channel_construction_bsc.py +++ b/gr-fec/python/fec/polar/channel_construction_bsc.py @@ -23,23 +23,6 @@ from helper_functions import * import matplotlib.pyplot as plt -# def bit_reverse(value, n): -# # is this really missing in NumPy??? -# bits = np.zeros(n, type(value)) -# for index in range(n): -# mask = 1 -# mask = np.left_shift(mask, index) -# bit = np.bitwise_and(value, mask) -# bit = np.right_shift(bit, index) -# bits[index] = bit -# bits = bits[::-1] -# result = 0 -# for index, bit in enumerate(bits): -# bit = np.left_shift(bit, index) -# result += bit -# return result - - def get_Bn(n): # this is a bit reversal matrix. lw = int(np.log2(n)) # number of used bits diff --git a/gr-fec/python/fec/polar/decoder.py b/gr-fec/python/fec/polar/decoder.py index d74f1f9e1a..ef7d70081f 100644 --- a/gr-fec/python/fec/polar/decoder.py +++ b/gr-fec/python/fec/polar/decoder.py @@ -122,16 +122,27 @@ class PolarDecoder(PolarCommon): u = np.append(u, ui) return u + def _llr_retrieve_bit(self, llr, pos): + f_index = np.where(self.frozen_bit_position == pos)[0] + if not f_index.size == 0: + ui = self.frozenbits[f_index][0] + else: + ui = self._llr_bit_decision(llr) + return ui + def _butterfly_decode_bits(self, pos, graph, u): + bit_num = u.size llr = graph[pos][0] - ui = self._llr_bit_decision(llr) + ui = self._llr_retrieve_bit(llr, bit_num) + # ui = self._llr_bit_decision(llr) u = np.append(u, ui) lower_right = pos + (self.N // 2) la = graph[pos][1] lb = graph[lower_right][1] graph[lower_right][0] = self._llr_even(la, lb, ui) llr = graph[lower_right][0] - ui = self._llr_bit_decision(llr) + # ui = self._llr_bit_decision(llr) + ui = self._llr_retrieve_bit(llr, u.size) u = np.append(u, ui) return graph, u diff --git a/gr-fec/python/fec/polar/helper_functions.py b/gr-fec/python/fec/polar/helper_functions.py index ffa4fc17dc..213f3cb7c0 100644 --- a/gr-fec/python/fec/polar/helper_functions.py +++ b/gr-fec/python/fec/polar/helper_functions.py @@ -19,6 +19,7 @@ # import numpy as np +from channel_construction_bec import get_bec_frozen_indices def is_power_of_two(num): @@ -72,7 +73,8 @@ def pack_byte(bits): def get_frozen_bit_positions(directory, n, k, p): import glob, os - os.chdir(directory) + if not os.getcwd().endswith(directory): + os.chdir(directory) prefix = 'frozen_bit_positions_' prefix_len = len(prefix) for file in glob.glob("*.npy"): @@ -90,7 +92,7 @@ def get_frozen_bit_positions(directory, n, k, p): pstr = float(pstr[0][1:]) if n == nstr and k == kstr: return np.load(filename) - return np.arange(k) + return get_bec_frozen_indices(n, k, p) def main(): diff --git a/gr-fec/python/fec/polar/testbed.py b/gr-fec/python/fec/polar/testbed.py index 4ace91ee47..bdf9ae437c 100755 --- a/gr-fec/python/fec/polar/testbed.py +++ b/gr-fec/python/fec/polar/testbed.py @@ -67,6 +67,24 @@ def approx_value(la, lb): return np.sign(la) * np.sign(lb) * np.minimum(np.abs(la), np.abs(lb)) +def path_metric_exact(last_pm, llr, ui): + return last_pm + np.log(1 + np.exp(-1. * llr * (1 - 2 * ui))) + + +def path_metric_approx(last_pm, llr, ui): + if ui == int(.5 * (1 - np.sign(llr))): + return last_pm + return last_pm + np.abs(llr) + + +def calculate_path_metric_vector(metric, llrs, us): + res = np.zeros(llrs.size) + res[0] = metric(0, llrs[0], us[0]) + for i in range(1, llrs.size): + res[i] = metric(res[i - 1], llrs[i], us[i]) + return res + + def test_1024_rate_1_code(): # effectively a Monte-Carlo simulation for channel polarization. ntests = 10000 @@ -135,11 +153,12 @@ def main(): # frozenbitposition = np.array((0, 1, 2, 3, 4, 5, 8, 9), dtype=int) # print frozenbitposition - test_enc_dec_chain() + # test_enc_dec_chain() # test_1024_rate_1_code() - # channel_analysis() + channel_analysis() + if __name__ == '__main__': main()
\ No newline at end of file diff --git a/gr-fec/python/fec/qa_polar_decoder_sc.py b/gr-fec/python/fec/qa_polar_decoder_sc.py new file mode 100644 index 0000000000..f26bf9a91a --- /dev/null +++ b/gr-fec/python/fec/qa_polar_decoder_sc.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python +# +# Copyright 2015 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# +from Crypto.Cipher._AES import block_size + +from gnuradio import gr, gr_unittest, blocks +import fec_swig as fec +from _qa_helper import _qa_helper +import numpy as np +import os + +from extended_encoder import extended_encoder +from extended_decoder import extended_decoder +from polar.encoder import PolarEncoder +from polar.decoder import PolarDecoder +from polar.helper_functions import get_frozen_bit_positions +# from polar.helper_functions import bit_reverse_vector + +# print('PID:', os.getpid()) +# raw_input('tell me smth') + +class test_polar_decoder_sc(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_001_setup(self): + is_packed = False + block_size = 16 + num_info_bits = 8 + frozen_bit_positions = np.arange(block_size - num_info_bits) + frozen_bit_values = np.array([],) + + polar_decoder = fec.polar_decoder_sc.make(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, is_packed) + + self.assertEqual(num_info_bits, polar_decoder.get_output_size()) + self.assertEqual(block_size, polar_decoder.get_input_size()) + self.assertFloatTuplesAlmostEqual((float(block_size) / num_info_bits, ), (polar_decoder.rate(), )) + self.assertFalse(polar_decoder.set_frame_size(10)) + + def test_002_one_vector(self): + print "test_002_one_vector" + is_packed = False + block_power = 8 + block_size = 2 ** block_power + num_info_bits = 2 ** (block_power - 1) + num_frozen_bits = block_size - num_info_bits + frozen_bit_positions = get_frozen_bit_positions('polar', block_size, num_frozen_bits, 0.11) + frozen_bit_values = np.array([0] * num_frozen_bits,) + print frozen_bit_positions + + python_decoder = PolarDecoder(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values) + + bits = np.ones(num_info_bits, dtype=int) + # bits = np.random.randint(2, size=num_info_bits) + encoder = PolarEncoder(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values) + data = encoder.encode(bits) + # data = np.array([0, 1, 1, 0, 1, 0, 1, 0], dtype=int) + gr_data = -2.0 * data + 1.0 + + polar_decoder = fec.polar_decoder_sc.make(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, is_packed) + src = blocks.vector_source_f(gr_data, False) + dec_block = extended_decoder(polar_decoder, None) + snk = blocks.vector_sink_b(1) + + self.tb.connect(src, dec_block) + self.tb.connect(dec_block, snk) + self.tb.run() + + res = np.array(snk.data()).astype(dtype=int) + + ref = python_decoder.decode(data) + + print("input:", data) + print("res :", res) + print("ref :", ref) + + self.assertTupleEqual(tuple(res), tuple(ref)) + + def test_003_stream(self): + print "test_002_stream" + nframes = 3 + is_packed = False + block_power = 8 + block_size = 2 ** block_power + num_info_bits = 2 ** (block_power - 1) + num_frozen_bits = block_size - num_info_bits + frozen_bit_positions = get_frozen_bit_positions('polar', block_size, num_frozen_bits, 0.11) + frozen_bit_values = np.array([0] * num_frozen_bits,) + print frozen_bit_positions + + python_decoder = PolarDecoder(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values) + encoder = PolarEncoder(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values) + + bits = np.array([], dtype=int) + data = np.array([], dtype=int) + for n in range(nframes): + b = np.random.randint(2, size=num_info_bits) + d = encoder.encode(b) + bits = np.append(bits, b) + data = np.append(data, d) + # bits = np.ones(num_info_bits, dtype=int) + # bits = np.random.randint(2, size=num_info_bits) + # data = encoder.encode(bits) + # data = np.array([0, 1, 1, 0, 1, 0, 1, 0], dtype=int) + gr_data = -2.0 * data + 1.0 + + polar_decoder = fec.polar_decoder_sc.make(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, is_packed) + src = blocks.vector_source_f(gr_data, False) + dec_block = extended_decoder(polar_decoder, None) + snk = blocks.vector_sink_b(1) + + self.tb.connect(src, dec_block) + self.tb.connect(dec_block, snk) + self.tb.run() + + res = np.array(snk.data()).astype(dtype=int) + + # ref = python_decoder.decode(data) + + print("input:", data) + print("res :", res) + # print("ref :", ref) + + self.assertTupleEqual(tuple(res), tuple(bits)) + + +if __name__ == '__main__': + gr_unittest.run(test_polar_decoder_sc) + + diff --git a/gr-fec/python/fec/qa_polar_decoder_sc_list.py b/gr-fec/python/fec/qa_polar_decoder_sc_list.py new file mode 100644 index 0000000000..f698a4e01c --- /dev/null +++ b/gr-fec/python/fec/qa_polar_decoder_sc_list.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python +# +# Copyright 2015 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +from gnuradio import gr, gr_unittest, blocks +import fec_swig as fec +import numpy as np +import os + +from extended_encoder import extended_encoder +from extended_decoder import extended_decoder +from polar.encoder import PolarEncoder +from polar.decoder import PolarDecoder +from polar.helper_functions import get_frozen_bit_positions +# from polar.helper_functions import bit_reverse_vector +# +# print('PID:', os.getpid()) +# raw_input('tell me smth') + +class test_polar_decoder_sc_list(gr_unittest.TestCase): + + def setUp(self): + self.tb = gr.top_block() + + def tearDown(self): + self.tb = None + + def test_001_setup(self): + is_packed = False + block_size = 16 + num_info_bits = 8 + max_list_size = 4 + frozen_bit_positions = np.arange(block_size - num_info_bits) + frozen_bit_values = np.array([],) + + polar_decoder = fec.polar_decoder_sc_list.make(max_list_size, block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, is_packed) + + self.assertEqual(num_info_bits, polar_decoder.get_output_size()) + self.assertEqual(block_size, polar_decoder.get_input_size()) + self.assertFloatTuplesAlmostEqual((float(block_size) / num_info_bits, ), (polar_decoder.rate(), )) + self.assertFalse(polar_decoder.set_frame_size(10)) + + def test_002_one_vector(self): + print "test_002_one_vector" + is_packed = False + expo = 6 + block_size = 2 ** expo + num_info_bits = 2 ** (expo - 1) + max_list_size = 2 ** (expo - 2) + num_frozen_bits = block_size - num_info_bits + frozen_bit_positions = get_frozen_bit_positions('polar', block_size, num_frozen_bits, 0.11) + frozen_bit_values = np.array([0] * num_frozen_bits,) + print(frozen_bit_positions) + + python_decoder = PolarDecoder(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values) + + # data = np.ones(block_size, dtype=int) + bits = np.random.randint(2, size=num_info_bits) + # bits = np.ones(num_info_bits, dtype=int) + encoder = PolarEncoder(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values) + data = encoder.encode(bits) + # data = np.array([0, 1, 1, 0, 1, 0, 1, 0], dtype=int) + gr_data = -2.0 * data + 1.0 + + polar_decoder = fec.polar_decoder_sc_list.make(max_list_size, block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, is_packed) + src = blocks.vector_source_f(gr_data, False) + dec_block = extended_decoder(polar_decoder, None) + snk = blocks.vector_sink_b(1) + + self.tb.connect(src, dec_block) + self.tb.connect(dec_block, snk) + self.tb.run() + + res = np.array(snk.data()).astype(dtype=int) + + ref = python_decoder.decode(data) + + print("input:", data) + print("res :", res) + print("ref :", ref) + print("bits :", bits) + + self.assertTupleEqual(tuple(res), tuple(ref)) + + def test_003_stream(self): + print "test_003_stream" + nframes = 5 + is_packed = False + expo = 8 + block_size = 2 ** expo + num_info_bits = 2 ** (expo - 1) + max_list_size = 2 ** (expo - 2) + num_frozen_bits = block_size - num_info_bits + frozen_bit_positions = get_frozen_bit_positions('polar', block_size, num_frozen_bits, 0.11) + frozen_bit_values = np.array([0] * num_frozen_bits,) + print(frozen_bit_positions) + + encoder = PolarEncoder(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values) + + # data = np.ones(block_size, dtype=int) + ref = np.array([], dtype=int) + data = np.array([], dtype=int) + for i in range(nframes): + b = np.random.randint(2, size=num_info_bits) + d = encoder.encode(b) + data = np.append(data, d) + ref = np.append(ref, b) + + # bits = np.ones(num_info_bits, dtype=int) + # data = encoder.encode(bits) + # data = np.array([0, 1, 1, 0, 1, 0, 1, 0], dtype=int) + gr_data = -2.0 * data + 1.0 + + polar_decoder = fec.polar_decoder_sc_list.make(max_list_size, block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, is_packed) + src = blocks.vector_source_f(gr_data, False) + dec_block = extended_decoder(polar_decoder, None) + snk = blocks.vector_sink_b(1) + + self.tb.connect(src, dec_block) + self.tb.connect(dec_block, snk) + self.tb.run() + + res = np.array(snk.data()).astype(dtype=int) + + + print("input:", data) + print("res :", res) + print("ref :", ref) + + self.assertTupleEqual(tuple(res), tuple(ref)) + + + + +if __name__ == '__main__': + gr_unittest.run(test_polar_decoder_sc_list) + + + diff --git a/gr-fec/python/fec/qa_polar_encoder.py b/gr-fec/python/fec/qa_polar_encoder.py index 03629354f0..4af193e2d4 100644 --- a/gr-fec/python/fec/qa_polar_encoder.py +++ b/gr-fec/python/fec/qa_polar_encoder.py @@ -22,14 +22,11 @@ from gnuradio import gr, gr_unittest, blocks import fec_swig as fec -from _qa_helper import _qa_helper import numpy as np from extended_encoder import extended_encoder -from extended_decoder import extended_decoder from polar.encoder import PolarEncoder from polar.helper_functions import get_frozen_bit_positions -from polar.helper_functions import bit_reverse_vector class test_polar_encoder(gr_unittest.TestCase): @@ -61,21 +58,17 @@ class test_polar_encoder(gr_unittest.TestCase): frozen_bit_values = np.array([0] * num_frozen_bits,) python_encoder = PolarEncoder(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values) - is_packed = False + is_packed = True polar_encoder = fec.polar_encoder.make(block_size, num_info_bits, frozen_bit_positions, frozen_bit_values, is_packed) data = np.ones(num_info_bits, dtype=int) src = blocks.vector_source_b(data, False) - packer = blocks.pack_k_bits_bb(8) enc_block = extended_encoder(polar_encoder, None, '11') - unpacker = blocks.unpack_k_bits_bb(8) snk = blocks.vector_sink_b(1) - if is_packed: - self.tb.connect(src, packer, enc_block, unpacker, snk) - else: - self.tb.connect(src, enc_block, snk) + self.tb.connect(src, enc_block, snk) self.tb.run() + print(self.tb.edge_list()) res = np.array(snk.data()).astype(dtype=int) penc = python_encoder.encode(data) @@ -85,7 +78,7 @@ class test_polar_encoder(gr_unittest.TestCase): self.assertTupleEqual(tuple(res), tuple(penc)) def test_003_big_input(self): - is_packed = False + is_packed = True num_blocks = 30 block_size = 256 num_info_bits = 128 @@ -106,19 +99,13 @@ class test_polar_encoder(gr_unittest.TestCase): src = blocks.vector_source_b(data, False) - packer = blocks.pack_k_bits_bb(8) enc_block = extended_encoder(polar_encoder, None, '11') - unpacker = blocks.unpack_k_bits_bb(8) snk = blocks.vector_sink_b(1) - if is_packed: - self.tb.connect(src, packer, enc_block, unpacker, snk) - else: - self.tb.connect(src, enc_block, snk) + self.tb.connect(src, enc_block, snk) self.tb.run() res = np.array(snk.data()).astype(dtype=int) - # penc = python_encoder.encode(data) print(res) print(ref) diff --git a/gr-fec/swig/fec_swig.i b/gr-fec/swig/fec_swig.i index b5735aae6f..a33e8d1efe 100644 --- a/gr-fec/swig/fec_swig.i +++ b/gr-fec/swig/fec_swig.i @@ -63,6 +63,10 @@ #include "gnuradio/fec/tpc_encoder.h" #include "gnuradio/fec/tpc_decoder.h" #include "gnuradio/fec/polar_encoder.h" +#include "gnuradio/fec/polar_decoder_sc.h" +#include "gnuradio/fec/polar_common.h" +#include "gnuradio/fec/polar_decoder_sc_list.h" +#include "gnuradio/fec/polar_decoder_common.h" %} %include "gnuradio/fec/generic_decoder.h" @@ -106,3 +110,7 @@ GR_SWIG_BLOCK_MAGIC2(fec, puncture_bb); GR_SWIG_BLOCK_MAGIC2(fec, puncture_ff); GR_SWIG_BLOCK_MAGIC2(fec, depuncture_bb); %include "gnuradio/fec/polar_encoder.h" +%include "gnuradio/fec/polar_decoder_sc.h" +%include "gnuradio/fec/polar_common.h" +%include "gnuradio/fec/polar_decoder_sc_list.h" +%include "gnuradio/fec/polar_decoder_common.h" |