![]() |
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 Fano sequential algorithm as described in 00021 Sequential Decoding of Convolutional Codes by Yunghsiang S. Han and Po-Ning Chen (algorithm p.26) 00022 web.ntpu.edu.tw/~yshan/book_chapter.pdf 00023 00024 Uses a node+edge combo code tree representation‎ 00025 00026 */ 00027 #ifndef __CC_FANO_DECODING_FA_H__ 00028 #define __CC_FANO_DECODING_FA_H__ 00029 00030 #include "CC_SequentialDecoding_FA.h" 00031 #include "CC_SequentialDecodingInternal_FA.h" 00032 #include "CC_Encoding_FA.h" 00033 #include "CCSoft_Exception.h" 00034 #include "CC_TreeNodeEdge_FA.h" 00035 #include "CC_ReliabilityMatrix.h" 00036 #include "Debug.h" 00037 00038 #include <cmath> 00039 #include <time.h> 00040 #include <algorithm> 00041 #include <iostream> 00042 #include <iomanip> 00043 00044 namespace ccsoft 00045 { 00046 00056 template<typename T_Register, typename T_IOSymbol, unsigned int N_k> 00057 class CC_FanoDecoding_FA : public CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k> ,public CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, bool, N_k> 00058 { 00059 public: 00073 CC_FanoDecoding_FA(const std::vector<unsigned int>& constraints, 00074 const std::vector<std::vector<T_Register> >& genpoly_representations, 00075 float _init_threshold, 00076 float _delta_threshold, 00077 unsigned int _tree_cache_size = 0, 00078 float _delta_init_threshold = 0.0) : 00079 CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k>(constraints, genpoly_representations), 00080 CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, bool, N_k>(), 00081 init_threshold(_init_threshold), 00082 cur_threshold(_init_threshold), 00083 root_threshold(_init_threshold), 00084 delta_threshold(_delta_threshold), 00085 solution_found(false), 00086 effective_node_count(0), 00087 nb_moves(0), 00088 tree_cache_size(_tree_cache_size), 00089 unloop(_delta_init_threshold < 0.0), 00090 delta_init_threshold(_delta_init_threshold) 00091 {} 00092 00096 virtual ~CC_FanoDecoding_FA() 00097 {} 00098 00103 void set_tree_cache_size(unsigned int _tree_cache_size) 00104 { 00105 tree_cache_size = _tree_cache_size; 00106 } 00107 00111 void reset() 00112 { 00113 ParentInternal::reset(); 00114 Parent::reset(); 00115 cur_threshold = init_threshold; 00116 solution_found = false; 00117 effective_node_count = 0; 00118 } 00119 00126 virtual bool decode(const CC_ReliabilityMatrix& relmat, std::vector<T_IOSymbol>& decoded_message) 00127 { 00128 FanoNodeEdge *node_edge_current, *node_edge_successor; 00129 00130 if (relmat.get_message_length() < Parent::encoding.get_m()) 00131 { 00132 throw CCSoft_Exception("Reliability Matrix should have a number of columns at least equal to the code constraint"); 00133 } 00134 00135 if (relmat.get_nb_symbols_log2() != Parent::encoding.get_n()) 00136 { 00137 throw CCSoft_Exception("Reliability Matrix is not compatible with code output symbol size"); 00138 } 00139 00140 reset(); 00141 ParentInternal::init_root(); // initialize root node 00142 Parent::node_count++; 00143 effective_node_count++; 00144 node_edge_current = ParentInternal::root_node; 00145 nb_moves = 0; 00146 00147 #ifdef _DEBUG 00148 timespec time1, time2; 00149 int time_option = CLOCK_REALTIME; 00150 clock_gettime(time_option, &time1); 00151 #endif 00152 00153 visit_node_forward(node_edge_current, relmat); 00154 00155 while (continue_process(node_edge_current, relmat)) 00156 { 00157 //std::cout << "T=" << cur_threshold << " depth=" << node_current->get_depth() << " node #" << node_current->get_id() << " Mc=" << node_current->get_path_metric() << std::endl; 00158 DEBUG_OUT(Parent::verbosity > 1, "T=" << cur_threshold << " depth=" << node_edge_current->get_depth() << " node #" << node_edge_current->get_id() << " Mc=" << node_edge_current->get_path_metric() << std::endl); 00159 00160 if (node_edge_current->get_depth() > Parent::max_depth) 00161 { 00162 Parent::max_depth = node_edge_current->get_depth(); 00163 } 00164 00165 if (node_edge_current == ParentInternal::root_node) 00166 { 00167 root_threshold = cur_threshold; 00168 } 00169 00170 nb_moves++; 00171 const std::array<FanoNodeEdge*, (1<<N_k)>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges(); 00172 typename std::array<FanoNodeEdge*, (1<<N_k)>::const_iterator ne_it = outgoing_node_edges.begin(); 00173 std::vector<FanoNodeEdge*> child_node_edges; 00174 00175 for (; ne_it != outgoing_node_edges.end(); ++ne_it) 00176 { 00177 if ((*ne_it) && !((*ne_it)->get_tag())) // not traversed back 00178 { 00179 child_node_edges.push_back(*ne_it); 00180 } 00181 } 00182 00183 if (child_node_edges.size() == 0) // exhausted forward paths 00184 { 00185 DEBUG_OUT(Parent::verbosity > 2, "exhaustion of forward paths at node #" << node_edge_current->get_id() << std::endl); 00186 node_edge_current = move_back_from_node_or_loosen_threshold(node_edge_current); 00187 continue; 00188 } 00189 00190 std::sort(child_node_edges.begin(), child_node_edges.end(), node_edge_pointer_ordering<FanoNodeEdge>); 00191 node_edge_successor = *child_node_edges.begin(); // best successor 00192 DEBUG_OUT(Parent::verbosity > 2, "best successor node #" << node_edge_successor->get_id() << " Ms=" << node_edge_successor->get_path_metric() << std::endl); 00193 00194 if (node_edge_successor->get_path_metric() >= cur_threshold) // Ms >= T 00195 { 00196 // move forward: 00197 DEBUG_OUT(Parent::verbosity > 2, "forward" << std::endl); 00198 FanoNodeEdge *node_predecessor = node_edge_current; 00199 node_edge_current = node_edge_successor; 00200 00201 // termination with solution 00202 if (node_edge_current->get_depth() == relmat.get_message_length() - 1) 00203 { 00204 Parent::codeword_score = node_edge_current->get_path_metric(); 00205 ParentInternal::back_track(node_edge_current, decoded_message, true); // back track from terminal node to retrieve decoded message 00206 solution_found = true; 00207 Parent::max_depth++; 00208 #ifdef _DEBUG 00209 clock_gettime(time_option, &time2); 00210 DEBUG_OUT(Parent::verbosity > 0, std::cout << "Decoding time: " << std::setw(12) << std::setprecision(9) << debug_get_time_difference(time2,time1) << " s" << std::endl); 00211 #endif 00212 return true; 00213 } 00214 00215 // threshold tightening for the new current node 00216 if (node_predecessor->get_path_metric() < cur_threshold + delta_threshold) 00217 { 00218 int nb_delta = int((node_edge_current->get_path_metric() - init_threshold) / delta_threshold); 00219 00220 if (nb_delta < 0) 00221 { 00222 cur_threshold = ((nb_delta - 1) * delta_threshold) + init_threshold; 00223 } 00224 else 00225 { 00226 cur_threshold = (nb_delta * delta_threshold) + init_threshold; 00227 } 00228 00229 DEBUG_OUT(Parent::verbosity > 2, "tightening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl); 00230 } 00231 00232 // create children nodes from the new current node 00233 visit_node_forward(node_edge_current, relmat); 00234 } 00235 else 00236 { 00237 node_edge_current = move_back_from_node_or_loosen_threshold(node_edge_current); 00238 } 00239 } 00240 00241 return false; 00242 } 00243 00249 virtual void print_stats(std::ostream& os, bool success) 00250 { 00251 std::cout << "score = " << Parent::get_score() 00252 << " cur.threshold = " << cur_threshold 00253 << " nodes = " << Parent::get_nb_nodes() 00254 << " eff.nodes = " << effective_node_count 00255 << " moves = " << nb_moves 00256 << " max depth = " << Parent::get_max_depth() << std::endl; 00257 std::cout << "_RES " << (success ? 1 : 0) << "," 00258 << Parent::get_score() << "," 00259 << cur_threshold << "," 00260 << Parent::get_nb_nodes() << "," 00261 << effective_node_count << "," 00262 << nb_moves << "," 00263 << Parent::get_max_depth() << std::endl; 00264 } 00265 00270 virtual void print_dot(std::ostream& os) 00271 { 00272 ParentInternal::print_dot_internal(os); 00273 } 00274 00275 protected: 00276 typedef CC_SequentialDecoding_FA<T_Register, T_IOSymbol, N_k> Parent; 00277 typedef CC_SequentialDecodingInternal_FA<T_Register, T_IOSymbol, bool, N_k> ParentInternal; 00278 typedef CC_TreeNodeEdge_FA<T_IOSymbol, T_Register, bool, N_k> FanoNodeEdge; 00279 00285 virtual void visit_node_forward(FanoNodeEdge* node_edge, const CC_ReliabilityMatrix& relmat) 00286 { 00287 unsigned int n = Parent::encoding.get_n(); 00288 int forward_depth = node_edge->get_depth() + 1; 00289 T_IOSymbol out_symbol; 00290 T_IOSymbol end_symbol; 00291 00292 // return encoder to appropriate state 00293 if (node_edge->get_depth() >= 0) // does not concern the root node_edge 00294 { 00295 Parent::encoding.set_registers(node_edge->get_registers()); 00296 } 00297 00298 if ((Parent::tail_zeros) && (forward_depth > relmat.get_message_length()-Parent::encoding.get_m())) 00299 { 00300 end_symbol = 1; // if zero tail option assume tail symbols are all zeros 00301 } 00302 else 00303 { 00304 end_symbol = (1<<Parent::encoding.get_k()); // full scan all possible input symbols 00305 } 00306 00307 if (!node_edge->valid_outgoing_node_edges(end_symbol)) // edges are not cached 00308 { 00309 if ((tree_cache_size > 0) && (effective_node_count >= tree_cache_size)) // if tree cache is used and cache limit reached 00310 { 00311 purge_tree_cache(node_edge); // purge before allocating new nodes 00312 } 00313 00314 // loop through assumption for this symbol place and create child nodes 00315 for (T_IOSymbol in_symbol = 0; in_symbol < end_symbol; in_symbol++) 00316 { 00317 Parent::encoding.encode(in_symbol, out_symbol, in_symbol > 0); // step only for a new symbol place 00318 float edge_metric = ParentInternal::log2(relmat(out_symbol, forward_depth)) - Parent::edge_bias; 00319 float forward_path_metric = edge_metric + node_edge->get_path_metric(); 00320 FanoNodeEdge *next_node_edge = new FanoNodeEdge(Parent::node_count++, node_edge, in_symbol, edge_metric, forward_path_metric, forward_depth); 00321 next_node_edge->get_tag() = false; // Init traversed back indicator 00322 next_node_edge->set_registers(Parent::encoding.get_registers()); 00323 node_edge->set_outgoing_node_edge(next_node_edge, in_symbol); // add forward edge 00324 effective_node_count++; 00325 } 00326 } 00327 } 00328 00335 FanoNodeEdge *move_back_from_node_or_loosen_threshold(FanoNodeEdge *node_edge_current) 00336 { 00337 if (node_edge_current == ParentInternal::root_node) // at root node there are no other options than loosening threshold 00338 { 00339 cur_threshold -= delta_threshold; 00340 DEBUG_OUT(Parent::verbosity > 2, "loosening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl); 00341 } 00342 else 00343 { 00344 FanoNodeEdge *node_edge_predecessor = node_edge_current->get_incoming_node_edge(); 00345 00346 if (node_edge_predecessor->get_path_metric() >= cur_threshold) // move backward 00347 { 00348 DEBUG_OUT(Parent::verbosity > 2, std::cout << "backward" << std::endl); 00349 00350 if (tree_cache_size == 0) // tree cache is not used 00351 { 00352 // delete all successor edges and nodes 00353 std::array<FanoNodeEdge*, (1<<N_k)>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges(); 00354 typename std::array<FanoNodeEdge*, (1<<N_k)>::iterator ne_it = outgoing_node_edges.begin(); 00355 00356 for (;ne_it != outgoing_node_edges.end(); ++ne_it) 00357 { 00358 delete *ne_it; 00359 } 00360 00361 effective_node_count -= outgoing_node_edges.size(); 00362 std::fill(outgoing_node_edges.begin(), outgoing_node_edges.end(), (FanoNodeEdge*) 0); 00363 //outgoing_node_edges.fill(0); 00364 } 00365 00366 // mark incoming edge as traversed back 00367 if (node_edge_predecessor != ParentInternal::root_node) 00368 { 00369 node_edge_current->get_tag() = true; 00370 } 00371 00372 // move back: change node address to previous node address 00373 node_edge_current = node_edge_predecessor; 00374 } 00375 else // loosen threshold 00376 { 00377 cur_threshold -= delta_threshold; 00378 DEBUG_OUT(Parent::verbosity > 2, "loosening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl); 00379 } 00380 } 00381 00382 return node_edge_current; 00383 } 00384 00388 bool continue_process(FanoNodeEdge *node_edge_current, const CC_ReliabilityMatrix& relmat) 00389 { 00390 if ((node_edge_current == ParentInternal::root_node) && (nb_moves > 0) && (cur_threshold == root_threshold)) 00391 { 00392 const std::array<FanoNodeEdge*, (1<<N_k)>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges(); 00393 typename std::array<FanoNodeEdge*, (1<<N_k)>::const_iterator ne_it = outgoing_node_edges.begin(); 00394 bool children_open = true; 00395 00396 for (; ne_it != outgoing_node_edges.end(); ++ne_it) 00397 { 00398 if ((*ne_it)->get_tag()) // traversed back 00399 { 00400 children_open = false; 00401 break; 00402 } 00403 } 00404 00405 if (children_open) 00406 { 00407 if (unloop && ((Parent::use_metric_limit) && (init_threshold > Parent::metric_limit))) 00408 { 00409 init_threshold += delta_init_threshold; // lower initial threshold and start all over again (delta if used is negative) 00410 Parent::reset(); // reset but do not delete root node 00411 cur_threshold = init_threshold; 00412 solution_found = false; 00413 ParentInternal::root_node->delete_outgoing_node_edges(); // effectively resets the root node without destroying it 00414 Parent::node_count = 1; 00415 effective_node_count = 1; 00416 nb_moves = 0; 00417 visit_node_forward(node_edge_current, relmat); // visit root node again 00418 std::cerr << "Loop condition detected, restart with init threshold = " << init_threshold << std::endl; 00419 return true; 00420 } 00421 else 00422 { 00423 std::cerr << "Loop condition detected, aborting" << std::endl; 00424 return false; 00425 } 00426 } 00427 } 00428 00429 if ((Parent::use_metric_limit) && (cur_threshold < Parent::metric_limit)) 00430 { 00431 std::cerr << "Metric limit encountered" << std::endl; 00432 return false; 00433 } 00434 00435 if ((Parent::use_node_limit) && (Parent::node_count > Parent::node_limit)) 00436 { 00437 std::cerr << "Node limit exhausted" << std::endl; 00438 return false; 00439 } 00440 00441 return true; 00442 } 00443 00448 void purge_tree_cache(FanoNodeEdge *node_edge) 00449 { 00450 bool node_terminal = true; 00451 unsigned int remaining_nodes = 0; 00452 00453 while (node_edge != ParentInternal::root_node) 00454 { 00455 FanoNodeEdge *node_edge_predecessor = node_edge->get_incoming_node_edge(); 00456 std::array<FanoNodeEdge*, (1<<N_k)>& outgoing_node_edges = node_edge_predecessor->get_outgoing_node_edges(); 00457 typename std::array<FanoNodeEdge*, (1<<N_k)>::iterator ne_it = outgoing_node_edges.begin(); 00458 00459 for (;ne_it != outgoing_node_edges.end(); ++ne_it) 00460 { 00461 if (*ne_it) // if using trailing zeros the corresponding edges for input symbol not zero are not constructed 00462 { 00463 FanoNodeEdge *node_edge_sibling = (*ne_it); 00464 00465 if (node_terminal || (node_edge_sibling != node_edge)) 00466 { 00467 (*ne_it)->delete_outgoing_node_edges(); 00468 } 00469 00470 remaining_nodes++; 00471 } 00472 } 00473 00474 node_edge = node_edge_predecessor; 00475 node_terminal = false; 00476 } 00477 00478 remaining_nodes++; // +1 for root node 00479 effective_node_count = remaining_nodes; 00480 DEBUG_OUT(Parent::verbosity > 1, "purged tree cache, nb of remaining nodes = " << remaining_nodes << std::endl); 00481 } 00482 00483 float init_threshold; 00484 float cur_threshold; 00485 float delta_threshold; 00486 bool solution_found; 00487 unsigned int effective_node_count; 00488 unsigned int nb_moves; 00489 float root_threshold; 00490 unsigned int tree_cache_size; 00491 bool unloop; 00492 float delta_init_threshold; 00493 }; 00494 00495 00496 00497 } // namespace ccsoft 00498 00499 #endif // __CC_FANO_DECODING_FA_H__