![]() |
ccsoft
0.0.0
Convolutional codes library with soft decision decoding
|
00001 /* 00002 Copyright 2013 Edouard Griffiths <f4exb at free dot fr> 00003 00004 This file is part of CCSoft. A Convolutional Codes Soft Decoding library 00005 00006 This program is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program; if not, write to the Free Software 00018 Foundation, Inc., 51 Franklin Street, Boston, MA 02110-1301 USA 00019 00020 Convolutional soft-decision decoder based on the stack or Zigangirov-Jelinek 00021 (ZJ) algorithm. Uses the node+edge combination in the code tree. 00022 00023 Uses fixed arrays 00024 00025 */ 00026 #ifndef __CC_STACK_DECODING_FA_H__ 00027 #define __CC_STACK_DECODING_FA_H__ 00028 00029 #include "CC_SequentialDecoding_FA.h" 00030 #include "CC_SequentialDecodingInternal_FA.h" 00031 #include "CC_Encoding_FA.h" 00032 #include "CCSoft_Exception.h" 00033 #include "CC_TreeNodeEdge_FA.h" 00034 #include "CC_ReliabilityMatrix.h" 00035 00036 #include <cmath> 00037 #include <map> 00038 #include <algorithm> 00039 #include <iostream> 00040 00041 00042 namespace ccsoft 00043 { 00044 00055 template<typename T_Register, typename T_IOSymbol, unsigned int N_k> 00056 class CC_StackDecoding_FA : public CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k>, public CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty, N_k> 00057 { 00058 public: 00068 CC_StackDecoding_FA(const std::vector<unsigned int>& constraints, 00069 const std::vector<std::vector<T_Register> >& genpoly_representations) : 00070 CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k>(constraints, genpoly_representations), 00071 CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty, N_k>() 00072 {} 00073 00077 virtual ~CC_StackDecoding_FA() 00078 {} 00079 00083 void reset() 00084 { 00085 ParentInternal::reset(); 00086 Parent::reset(); 00087 node_edge_stack.clear(); 00088 } 00089 00093 float get_stack_score() const 00094 { 00095 return node_edge_stack.begin()->first.path_metric; 00096 } 00097 00101 unsigned int get_stack_size() const 00102 { 00103 return node_edge_stack.size(); 00104 } 00105 00111 virtual bool decode(const CC_ReliabilityMatrix& relmat, std::vector<T_IOSymbol>& decoded_message) 00112 { 00113 if (relmat.get_message_length() < Parent::encoding.get_m()) 00114 { 00115 throw CCSoft_Exception("Reliability Matrix should have a number of columns at least equal to the code constraint"); 00116 } 00117 00118 if (relmat.get_nb_symbols_log2() != Parent::encoding.get_n()) 00119 { 00120 throw CCSoft_Exception("Reliability Matrix is not compatible with code output symbol size"); 00121 } 00122 00123 reset(); 00124 ParentInternal::init_root(); // initialize the root node 00125 Parent::node_count++; 00126 visit_node_forward(ParentInternal::root_node, relmat); // visit the root node 00127 00128 // loop until we get to a terminal node or the metric limit is encountered hence the stack is empty 00129 while ((node_edge_stack.size() > 0) 00130 && (node_edge_stack.begin()->second->get_depth() < relmat.get_message_length() - 1)) 00131 { 00132 StackNodeEdge* node = node_edge_stack.begin()->second; 00133 //std::cout << std::dec << node->get_id() << ":" << node->get_depth() << ":" << node_stack.begin()->first.path_metric << std::endl; 00134 visit_node_forward(node, relmat); 00135 00136 if ((Parent::use_node_limit) && (Parent::node_count > Parent::node_limit)) 00137 { 00138 std::cerr << "Node limit exhausted" << std::endl; 00139 return false; 00140 } 00141 } 00142 00143 // Top node has the solution if we have not given up 00144 if (!Parent::use_metric_limit || node_edge_stack.size() != 0) 00145 { 00146 //std::cout << "final: " << std::dec << node_stack.begin()->second->get_id() << ":" << node_stack.begin()->second->get_depth() << ":" << node_stack.begin()->first.path_metric << std::endl; 00147 ParentInternal::back_track(node_edge_stack.begin()->second, decoded_message, true); // back track from terminal node to retrieve decoded message 00148 Parent::codeword_score = node_edge_stack.begin()->first.path_metric; // the codeword score is the path metric 00149 return true; 00150 } 00151 else 00152 { 00153 std::cerr << "Metric limit encountered" << std::endl; 00154 return false; // no solution 00155 } 00156 } 00157 00163 virtual void print_stats(std::ostream& os, bool success) 00164 { 00165 std::cout << "score = " << Parent::get_score() 00166 << " stack_score = " << get_stack_score() 00167 << " #nodes = " << Parent::get_nb_nodes() 00168 << " stack_size = " << get_stack_size() 00169 << " max depth = " << Parent::get_max_depth() << std::endl; 00170 std::cout << "_RES " << (success ? 1 : 0) << "," 00171 << Parent::get_score() << "," 00172 << get_stack_score() << "," 00173 << Parent::get_nb_nodes() << "," 00174 << get_stack_size() << "," 00175 << Parent::get_max_depth() << std::endl; 00176 } 00177 00182 virtual void print_dot(std::ostream& os) 00183 { 00184 ParentInternal::print_dot_internal(os); 00185 } 00186 00187 protected: 00188 typedef CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k> Parent; 00189 typedef CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty, N_k> ParentInternal; 00190 typedef CC_TreeNodeEdge_FA<T_IOSymbol, T_Register, CC_TreeNodeEdgeTag_Empty, N_k> StackNodeEdge; 00191 00197 virtual void visit_node_forward(CC_TreeNodeEdge_FA<T_IOSymbol, T_Register, CC_TreeNodeEdgeTag_Empty, N_k>* node_edge, const CC_ReliabilityMatrix& relmat) 00198 { 00199 int forward_depth = node_edge->get_depth() + 1; 00200 T_IOSymbol out_symbol; 00201 T_IOSymbol end_symbol; 00202 00203 // return encoder to appropriate state 00204 if (node_edge->get_depth() >= 0) // does not concern the root node 00205 { 00206 Parent::encoding.set_registers(node_edge->get_registers()); 00207 } 00208 00209 if ((Parent::tail_zeros) && (forward_depth > relmat.get_message_length()-Parent::encoding.get_m())) 00210 { 00211 end_symbol = 1; // if zero tail option assume tail symbols are all zeros 00212 } 00213 else 00214 { 00215 end_symbol = (1<<Parent::encoding.get_k()); // full scan all possible input symbols 00216 } 00217 00218 // loop through assumption for this symbol place 00219 for (T_IOSymbol in_symbol = 0; in_symbol < end_symbol; in_symbol++) 00220 { 00221 Parent::encoding.encode(in_symbol, out_symbol, in_symbol > 0); // step only for a new symbol place 00222 float edge_metric = ParentInternal::log2(relmat(out_symbol, forward_depth)) - Parent::edge_bias; 00223 00224 float forward_path_metric = edge_metric + node_edge->get_path_metric(); 00225 if ((!Parent::use_metric_limit) || (forward_path_metric > Parent::metric_limit)) 00226 { 00227 StackNodeEdge *next_node_edge = new StackNodeEdge(Parent::node_count, node_edge, in_symbol, edge_metric, forward_path_metric, forward_depth); 00228 next_node_edge->set_registers(Parent::encoding.get_registers()); 00229 node_edge->set_outgoing_node_edge(next_node_edge, in_symbol); // add forward edge+node combo 00230 node_edge_stack[NodeEdgeOrdering(forward_path_metric, Parent::node_count)] = next_node_edge; 00231 //std::cout << "->" << std::dec << node_count << ":" << forward_depth << " (" << (unsigned int) in_symbol << "," << (unsigned int) out_symbol << "): " << forward_path_metric << std::endl; 00232 Parent::node_count++; 00233 } 00234 } 00235 00236 Parent::cur_depth = forward_depth; // new encoder position 00237 00238 if (Parent::cur_depth > Parent::max_depth) 00239 { 00240 Parent::max_depth = Parent::cur_depth; 00241 } 00242 00243 if (node_edge->get_depth() >= 0) 00244 { 00245 remove_node_from_stack(node_edge); // remove current node from the stack unless it is the root node which is not in the stack 00246 } 00247 } 00248 00252 void remove_node_from_stack(StackNodeEdge* node_edge) 00253 { 00254 typename std::map<NodeEdgeOrdering, StackNodeEdge*, std::greater<NodeEdgeOrdering> >::iterator stack_it = node_edge_stack.begin(); 00255 00256 for (; stack_it != node_edge_stack.end(); ++stack_it) 00257 { 00258 if (node_edge == stack_it->second) 00259 { 00260 node_edge_stack.erase(stack_it); 00261 break; 00262 } 00263 } 00264 } 00265 00266 std::map<NodeEdgeOrdering, StackNodeEdge*, std::greater<NodeEdgeOrdering> > node_edge_stack; 00267 }; 00268 00269 } // namespace ccsoft 00270 00271 #endif