![]() |
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 */ 00024 #ifndef __CC_STACK_DECODING_H__ 00025 #define __CC_STACK_DECODING_H__ 00026 00027 #include "CC_SequentialDecoding.h" 00028 #include "CC_SequentialDecodingInternal.h" 00029 #include "CC_Encoding.h" 00030 #include "CCSoft_Exception.h" 00031 #include "CC_TreeNodeEdge.h" 00032 #include "CC_ReliabilityMatrix.h" 00033 00034 #include <cmath> 00035 #include <map> 00036 #include <algorithm> 00037 #include <iostream> 00038 00039 00040 namespace ccsoft 00041 { 00042 00048 template<typename T_Register, typename T_IOSymbol> 00049 class CC_StackDecoding : public CC_SequentialDecoding<T_Register, T_IOSymbol>, public CC_SequentialDecodingInternal<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty> 00050 { 00051 public: 00061 CC_StackDecoding(const std::vector<unsigned int>& constraints, 00062 const std::vector<std::vector<T_Register> >& genpoly_representations) : 00063 CC_SequentialDecoding<T_Register, T_IOSymbol>(constraints, genpoly_representations), 00064 CC_SequentialDecodingInternal<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty>() 00065 {} 00066 00070 virtual ~CC_StackDecoding() 00071 {} 00072 00076 void reset() 00077 { 00078 ParentInternal::reset(); 00079 Parent::reset(); 00080 node_edge_stack.clear(); 00081 } 00082 00086 float get_stack_score() const 00087 { 00088 return node_edge_stack.begin()->first.path_metric; 00089 } 00090 00094 unsigned int get_stack_size() const 00095 { 00096 return node_edge_stack.size(); 00097 } 00098 00104 virtual bool decode(const CC_ReliabilityMatrix& relmat, std::vector<T_IOSymbol>& decoded_message) 00105 { 00106 if (relmat.get_message_length() < Parent::encoding.get_m()) 00107 { 00108 throw CCSoft_Exception("Reliability Matrix should have a number of columns at least equal to the code constraint"); 00109 } 00110 00111 if (relmat.get_nb_symbols_log2() != Parent::encoding.get_n()) 00112 { 00113 throw CCSoft_Exception("Reliability Matrix is not compatible with code output symbol size"); 00114 } 00115 00116 reset(); 00117 ParentInternal::init_root(); // initialize the root node 00118 Parent::node_count++; 00119 visit_node_forward(ParentInternal::root_node, relmat); // visit the root node 00120 00121 // loop until we get to a terminal node or the metric limit is encountered hence the stack is empty 00122 while ((node_edge_stack.size() > 0) 00123 && (node_edge_stack.begin()->second->get_depth() < relmat.get_message_length() - 1)) 00124 { 00125 StackNodeEdge* node = node_edge_stack.begin()->second; 00126 //std::cout << std::dec << node->get_id() << ":" << node->get_depth() << ":" << node_stack.begin()->first.path_metric << std::endl; 00127 visit_node_forward(node, relmat); 00128 00129 if ((Parent::use_node_limit) && (Parent::node_count > Parent::node_limit)) 00130 { 00131 std::cerr << "Node limit exhausted" << std::endl; 00132 return false; 00133 } 00134 } 00135 00136 // Top node has the solution if we have not given up 00137 if (!Parent::use_metric_limit || node_edge_stack.size() != 0) 00138 { 00139 //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; 00140 ParentInternal::back_track(node_edge_stack.begin()->second, decoded_message, true); // back track from terminal node to retrieve decoded message 00141 Parent::codeword_score = node_edge_stack.begin()->first.path_metric; // the codeword score is the path metric 00142 return true; 00143 } 00144 else 00145 { 00146 std::cerr << "Metric limit encountered" << std::endl; 00147 return false; // no solution 00148 } 00149 } 00150 00156 virtual void print_stats(std::ostream& os, bool success) 00157 { 00158 std::cout << "score = " << Parent::get_score() 00159 << " stack_score = " << get_stack_score() 00160 << " #nodes = " << Parent::get_nb_nodes() 00161 << " stack_size = " << get_stack_size() 00162 << " max depth = " << Parent::get_max_depth() << std::endl; 00163 std::cout << "_RES " << (success ? 1 : 0) << "," 00164 << Parent::get_score() << "," 00165 << get_stack_score() << "," 00166 << Parent::get_nb_nodes() << "," 00167 << get_stack_size() << "," 00168 << Parent::get_max_depth() << std::endl; 00169 } 00170 00175 virtual void print_dot(std::ostream& os) 00176 { 00177 ParentInternal::print_dot_internal(os); 00178 } 00179 00180 protected: 00181 typedef CC_SequentialDecoding<T_Register, T_IOSymbol> Parent; 00182 typedef CC_SequentialDecodingInternal<T_Register, T_IOSymbol, CC_TreeNodeEdgeTag_Empty> ParentInternal; 00183 typedef CC_TreeNodeEdge<T_IOSymbol, T_Register, CC_TreeNodeEdgeTag_Empty> StackNodeEdge; 00184 00190 virtual void visit_node_forward(CC_TreeNodeEdge<T_IOSymbol, T_Register, CC_TreeNodeEdgeTag_Empty>* node_edge, const CC_ReliabilityMatrix& relmat) 00191 { 00192 int forward_depth = node_edge->get_depth() + 1; 00193 T_IOSymbol out_symbol; 00194 T_IOSymbol end_symbol; 00195 00196 // return encoder to appropriate state 00197 if (node_edge->get_depth() >= 0) // does not concern the root node 00198 { 00199 Parent::encoding.set_registers(node_edge->get_registers()); 00200 } 00201 00202 if ((Parent::tail_zeros) && (forward_depth > relmat.get_message_length()-Parent::encoding.get_m())) 00203 { 00204 end_symbol = 1; // if zero tail option assume tail symbols are all zeros 00205 } 00206 else 00207 { 00208 end_symbol = (1<<Parent::encoding.get_k()); // full scan all possible input symbols 00209 } 00210 00211 // loop through assumption for this symbol place 00212 for (T_IOSymbol in_symbol = 0; in_symbol < end_symbol; in_symbol++) 00213 { 00214 Parent::encoding.encode(in_symbol, out_symbol, in_symbol > 0); // step only for a new symbol place 00215 float edge_metric = ParentInternal::log2(relmat(out_symbol, forward_depth)) - Parent::edge_bias; 00216 00217 float forward_path_metric = edge_metric + node_edge->get_path_metric(); 00218 if ((!Parent::use_metric_limit) || (forward_path_metric > Parent::metric_limit)) 00219 { 00220 StackNodeEdge *next_node_edge = new StackNodeEdge(Parent::node_count, node_edge, in_symbol, edge_metric, forward_path_metric, forward_depth); 00221 next_node_edge->set_registers(Parent::encoding.get_registers()); 00222 node_edge->add_outgoing_node_edge(next_node_edge); // add forward edge+node combo 00223 node_edge_stack[NodeEdgeOrdering(forward_path_metric, Parent::node_count)] = next_node_edge; 00224 //std::cout << "->" << std::dec << node_count << ":" << forward_depth << " (" << (unsigned int) in_symbol << "," << (unsigned int) out_symbol << "): " << forward_path_metric << std::endl; 00225 Parent::node_count++; 00226 } 00227 } 00228 00229 Parent::cur_depth = forward_depth; // new encoder position 00230 00231 if (Parent::cur_depth > Parent::max_depth) 00232 { 00233 Parent::max_depth = Parent::cur_depth; 00234 } 00235 00236 if (node_edge->get_depth() >= 0) 00237 { 00238 remove_node_from_stack(node_edge); // remove current node from the stack unless it is the root node which is not in the stack 00239 } 00240 } 00241 00245 void remove_node_from_stack(StackNodeEdge* node_edge) 00246 { 00247 typename std::map<NodeEdgeOrdering, StackNodeEdge*, std::greater<NodeEdgeOrdering> >::iterator stack_it = node_edge_stack.begin(); 00248 00249 for (; stack_it != node_edge_stack.end(); ++stack_it) 00250 { 00251 if (node_edge == stack_it->second) 00252 { 00253 node_edge_stack.erase(stack_it); 00254 break; 00255 } 00256 } 00257 } 00258 00259 std::map<NodeEdgeOrdering, StackNodeEdge*, std::greater<NodeEdgeOrdering> > node_edge_stack; 00260 }; 00261 00262 } // namespace ccsoft 00263 00264 #endif