![]() |
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_H__ 00028 #define __CC_FANO_DECODING_H__ 00029 00030 #include "CC_SequentialDecoding.h" 00031 #include "CC_SequentialDecodingInternal.h" 00032 #include "CC_Encoding.h" 00033 #include "CCSoft_Exception.h" 00034 #include "CC_TreeNodeEdge.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 00052 template<typename T_Register, typename T_IOSymbol> 00053 class CC_FanoDecoding : public CC_SequentialDecoding<T_Register, T_IOSymbol> ,public CC_SequentialDecodingInternal<T_Register, T_IOSymbol, bool> 00054 { 00055 public: 00069 CC_FanoDecoding(const std::vector<unsigned int>& constraints, 00070 const std::vector<std::vector<T_Register> >& genpoly_representations, 00071 float _init_threshold, 00072 float _delta_threshold, 00073 unsigned int _tree_cache_size = 0, 00074 float _delta_init_threshold = 0.0) : 00075 CC_SequentialDecoding<T_Register, T_IOSymbol>(constraints, genpoly_representations), 00076 CC_SequentialDecodingInternal<T_Register, T_IOSymbol, bool>(), 00077 init_threshold(_init_threshold), 00078 cur_threshold(_init_threshold), 00079 root_threshold(_init_threshold), 00080 delta_threshold(_delta_threshold), 00081 solution_found(false), 00082 effective_node_count(0), 00083 nb_moves(0), 00084 tree_cache_size(_tree_cache_size), 00085 unloop(_delta_init_threshold < 0.0), 00086 delta_init_threshold(_delta_init_threshold) 00087 {} 00088 00092 virtual ~CC_FanoDecoding() 00093 {} 00094 00099 void set_tree_cache_size(unsigned int _tree_cache_size) 00100 { 00101 tree_cache_size = _tree_cache_size; 00102 } 00103 00107 void reset() 00108 { 00109 ParentInternal::reset(); 00110 Parent::reset(); 00111 cur_threshold = init_threshold; 00112 solution_found = false; 00113 effective_node_count = 0; 00114 } 00115 00122 virtual bool decode(const CC_ReliabilityMatrix& relmat, std::vector<T_IOSymbol>& decoded_message) 00123 { 00124 FanoNodeEdge *node_edge_current, *node_edge_successor; 00125 00126 if (relmat.get_message_length() < Parent::encoding.get_m()) 00127 { 00128 throw CCSoft_Exception("Reliability Matrix should have a number of columns at least equal to the code constraint"); 00129 } 00130 00131 if (relmat.get_nb_symbols_log2() != Parent::encoding.get_n()) 00132 { 00133 throw CCSoft_Exception("Reliability Matrix is not compatible with code output symbol size"); 00134 } 00135 00136 reset(); 00137 ParentInternal::init_root(); // initialize root node 00138 Parent::node_count++; 00139 effective_node_count++; 00140 node_edge_current = ParentInternal::root_node; 00141 nb_moves = 0; 00142 00143 #ifdef _DEBUG 00144 timespec time1, time2; 00145 int time_option = CLOCK_REALTIME; 00146 clock_gettime(time_option, &time1); 00147 #endif 00148 00149 visit_node_forward(node_edge_current, relmat); 00150 00151 while (continue_process(node_edge_current, relmat)) 00152 { 00153 //std::cout << "T=" << cur_threshold << " depth=" << node_current->get_depth() << " node #" << node_current->get_id() << " Mc=" << node_current->get_path_metric() << std::endl; 00154 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); 00155 00156 if (node_edge_current->get_depth() > Parent::max_depth) 00157 { 00158 Parent::max_depth = node_edge_current->get_depth(); 00159 } 00160 00161 if (node_edge_current == ParentInternal::root_node) 00162 { 00163 root_threshold = cur_threshold; 00164 } 00165 00166 nb_moves++; 00167 const std::vector<FanoNodeEdge*>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges(); 00168 typename std::vector<FanoNodeEdge*>::const_iterator ne_it = outgoing_node_edges.begin(); 00169 std::vector<FanoNodeEdge*> child_node_edges; 00170 00171 for (; ne_it != outgoing_node_edges.end(); ++ne_it) 00172 { 00173 if (!((*ne_it)->get_tag())) // not traversed back 00174 { 00175 child_node_edges.push_back(*ne_it); 00176 } 00177 } 00178 00179 if (child_node_edges.size() == 0) // exhausted forward paths 00180 { 00181 DEBUG_OUT(Parent::verbosity > 2, "exhaustion of forward paths at node #" << node_edge_current->get_id() << std::endl); 00182 node_edge_current = move_back_from_node_or_loosen_threshold(node_edge_current); 00183 continue; 00184 } 00185 00186 std::sort(child_node_edges.begin(), child_node_edges.end(), node_edge_pointer_ordering<FanoNodeEdge>); 00187 node_edge_successor = *child_node_edges.begin(); // best successor 00188 DEBUG_OUT(Parent::verbosity > 2, "best successor node #" << node_edge_successor->get_id() << " Ms=" << node_edge_successor->get_path_metric() << std::endl); 00189 00190 if (node_edge_successor->get_path_metric() >= cur_threshold) // Ms >= T 00191 { 00192 // move forward: 00193 DEBUG_OUT(Parent::verbosity > 2, "forward" << std::endl); 00194 FanoNodeEdge *node_predecessor = node_edge_current; 00195 node_edge_current = node_edge_successor; 00196 00197 // termination with solution 00198 if (node_edge_current->get_depth() == relmat.get_message_length() - 1) 00199 { 00200 Parent::codeword_score = node_edge_current->get_path_metric(); 00201 ParentInternal::back_track(node_edge_current, decoded_message, true); // back track from terminal node to retrieve decoded message 00202 solution_found = true; 00203 Parent::max_depth++; 00204 #ifdef _DEBUG 00205 clock_gettime(time_option, &time2); 00206 DEBUG_OUT(Parent::verbosity > 0, std::cout << "Decoding time: " << std::setw(12) << std::setprecision(9) << debug_get_time_difference(time2,time1) << " s" << std::endl); 00207 #endif 00208 return true; 00209 } 00210 00211 // threshold tightening for the new current node 00212 if (node_predecessor->get_path_metric() < cur_threshold + delta_threshold) 00213 { 00214 int nb_delta = int((node_edge_current->get_path_metric() - init_threshold) / delta_threshold); 00215 00216 if (nb_delta < 0) 00217 { 00218 cur_threshold = ((nb_delta - 1) * delta_threshold) + init_threshold; 00219 } 00220 else 00221 { 00222 cur_threshold = (nb_delta * delta_threshold) + init_threshold; 00223 } 00224 00225 DEBUG_OUT(Parent::verbosity > 2, "tightening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl); 00226 } 00227 00228 // create children nodes from the new current node 00229 visit_node_forward(node_edge_current, relmat); 00230 } 00231 else 00232 { 00233 node_edge_current = move_back_from_node_or_loosen_threshold(node_edge_current); 00234 } 00235 } 00236 00237 return false; 00238 } 00239 00245 virtual void print_stats(std::ostream& os, bool success) 00246 { 00247 std::cout << "score = " << Parent::get_score() 00248 << " cur.threshold = " << cur_threshold 00249 << " nodes = " << Parent::get_nb_nodes() 00250 << " eff.nodes = " << effective_node_count 00251 << " moves = " << nb_moves 00252 << " max depth = " << Parent::get_max_depth() << std::endl; 00253 std::cout << "_RES " << (success ? 1 : 0) << "," 00254 << Parent::get_score() << "," 00255 << cur_threshold << "," 00256 << Parent::get_nb_nodes() << "," 00257 << effective_node_count << "," 00258 << nb_moves << "," 00259 << Parent::get_max_depth() << std::endl; 00260 } 00261 00266 virtual void print_dot(std::ostream& os) 00267 { 00268 ParentInternal::print_dot_internal(os); 00269 } 00270 00271 protected: 00272 typedef CC_SequentialDecoding<T_Register, T_IOSymbol> Parent; 00273 typedef CC_SequentialDecodingInternal<T_Register, T_IOSymbol, bool> ParentInternal; 00274 typedef CC_TreeNodeEdge<T_IOSymbol, T_Register, bool> FanoNodeEdge; 00275 00281 virtual void visit_node_forward(FanoNodeEdge* node_edge, const CC_ReliabilityMatrix& relmat) 00282 { 00283 unsigned int n = Parent::encoding.get_n(); 00284 int forward_depth = node_edge->get_depth() + 1; 00285 T_IOSymbol out_symbol; 00286 T_IOSymbol end_symbol; 00287 00288 // return encoder to appropriate state 00289 if (node_edge->get_depth() >= 0) // does not concern the root node_edge 00290 { 00291 Parent::encoding.set_registers(node_edge->get_registers()); 00292 } 00293 00294 if ((Parent::tail_zeros) && (forward_depth > relmat.get_message_length()-Parent::encoding.get_m())) 00295 { 00296 end_symbol = 1; // if zero tail option assume tail symbols are all zeros 00297 } 00298 else 00299 { 00300 end_symbol = (1<<Parent::encoding.get_k()); // full scan all possible input symbols 00301 } 00302 00303 if (node_edge->get_outgoing_node_edges().size() == 0) // edges are not cached 00304 { 00305 if ((tree_cache_size > 0) && (effective_node_count >= tree_cache_size)) // if tree cache is used and cache limit reached 00306 { 00307 purge_tree_cache(node_edge); // purge before allocating new nodes 00308 } 00309 00310 // loop through assumption for this symbol place and create child nodes 00311 for (T_IOSymbol in_symbol = 0; in_symbol < end_symbol; in_symbol++) 00312 { 00313 Parent::encoding.encode(in_symbol, out_symbol, in_symbol > 0); // step only for a new symbol place 00314 float edge_metric = ParentInternal::log2(relmat(out_symbol, forward_depth)) - Parent::edge_bias; 00315 float forward_path_metric = edge_metric + node_edge->get_path_metric(); 00316 FanoNodeEdge *next_node_edge = new FanoNodeEdge(Parent::node_count++, node_edge, in_symbol, edge_metric, forward_path_metric, forward_depth); 00317 next_node_edge->get_tag() = false; // Init traversed back indicator 00318 next_node_edge->set_registers(Parent::encoding.get_registers()); 00319 node_edge->add_outgoing_node_edge(next_node_edge); // add forward edge 00320 effective_node_count++; 00321 } 00322 } 00323 } 00324 00331 FanoNodeEdge *move_back_from_node_or_loosen_threshold(FanoNodeEdge *node_edge_current) 00332 { 00333 if (node_edge_current == ParentInternal::root_node) // at root node there are no other options than loosening threshold 00334 { 00335 cur_threshold -= delta_threshold; 00336 DEBUG_OUT(Parent::verbosity > 2, "loosening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl); 00337 } 00338 else 00339 { 00340 FanoNodeEdge *node_edge_predecessor = node_edge_current->get_incoming_node_edge(); 00341 00342 if (node_edge_predecessor->get_path_metric() >= cur_threshold) // move backward 00343 { 00344 DEBUG_OUT(Parent::verbosity > 2, std::cout << "backward" << std::endl); 00345 00346 if (tree_cache_size == 0) // tree cache is not used 00347 { 00348 // delete all successor edges and nodes 00349 std::vector<FanoNodeEdge*>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges(); 00350 typename std::vector<FanoNodeEdge*>::iterator ne_it = outgoing_node_edges.begin(); 00351 00352 for (;ne_it != outgoing_node_edges.end(); ++ne_it) 00353 { 00354 delete *ne_it; 00355 } 00356 00357 effective_node_count -= outgoing_node_edges.size(); 00358 outgoing_node_edges.clear(); 00359 } 00360 00361 // mark incoming edge as traversed back 00362 if (node_edge_predecessor != ParentInternal::root_node) 00363 { 00364 node_edge_current->get_tag() = true; 00365 } 00366 00367 // move back: change node address to previous node address 00368 node_edge_current = node_edge_predecessor; 00369 } 00370 else // loosen threshold 00371 { 00372 cur_threshold -= delta_threshold; 00373 DEBUG_OUT(Parent::verbosity > 2, "loosening " << node_edge_current->get_path_metric() << " -> " << cur_threshold << std::endl); 00374 } 00375 } 00376 00377 return node_edge_current; 00378 } 00379 00383 bool continue_process(FanoNodeEdge *node_edge_current, const CC_ReliabilityMatrix& relmat) 00384 { 00385 if ((node_edge_current == ParentInternal::root_node) && (nb_moves > 0) && (cur_threshold == root_threshold)) 00386 { 00387 const std::vector<FanoNodeEdge*>& outgoing_node_edges = node_edge_current->get_outgoing_node_edges(); 00388 typename std::vector<FanoNodeEdge*>::const_iterator ne_it = outgoing_node_edges.begin(); 00389 bool children_open = true; 00390 00391 for (; ne_it != outgoing_node_edges.end(); ++ne_it) 00392 { 00393 if ((*ne_it)->get_tag()) // traversed back 00394 { 00395 children_open = false; 00396 break; 00397 } 00398 } 00399 00400 if (children_open) 00401 { 00402 if (unloop && ((Parent::use_metric_limit) && (init_threshold > Parent::metric_limit))) 00403 { 00404 init_threshold += delta_init_threshold; // lower initial threshold and start all over again (delta if used is negative) 00405 Parent::reset(); // reset but do not delete root node 00406 cur_threshold = init_threshold; 00407 solution_found = false; 00408 ParentInternal::root_node->delete_outgoing_node_edges(); // effectively resets the root node without destroying it 00409 Parent::node_count = 1; 00410 effective_node_count = 1; 00411 nb_moves = 0; 00412 visit_node_forward(node_edge_current, relmat); // visit root node again 00413 std::cerr << "Loop condition detected, restart with init threshold = " << init_threshold << std::endl; 00414 return true; 00415 } 00416 else 00417 { 00418 std::cerr << "Loop condition detected, aborting" << std::endl; 00419 return false; 00420 } 00421 } 00422 } 00423 00424 if ((Parent::use_metric_limit) && (cur_threshold < Parent::metric_limit)) 00425 { 00426 std::cerr << "Metric limit encountered" << std::endl; 00427 return false; 00428 } 00429 00430 if ((Parent::use_node_limit) && (Parent::node_count > Parent::node_limit)) 00431 { 00432 std::cerr << "Node limit exhausted" << std::endl; 00433 return false; 00434 } 00435 00436 return true; 00437 } 00438 00443 void purge_tree_cache(FanoNodeEdge *node_edge) 00444 { 00445 bool node_terminal = true; 00446 unsigned int remaining_nodes = 0; 00447 00448 while (node_edge != ParentInternal::root_node) 00449 { 00450 FanoNodeEdge *node_edge_predecessor = node_edge->get_incoming_node_edge(); 00451 std::vector<FanoNodeEdge*>& outgoing_node_edges = node_edge_predecessor->get_outgoing_node_edges(); 00452 typename std::vector<FanoNodeEdge*>::iterator ne_it = outgoing_node_edges.begin(); 00453 00454 for (;ne_it != outgoing_node_edges.end(); ++ne_it) 00455 { 00456 FanoNodeEdge *node_edge_sibling = (*ne_it); 00457 00458 if (node_terminal || (node_edge_sibling != node_edge)) 00459 { 00460 (*ne_it)->delete_outgoing_node_edges(); 00461 } 00462 00463 remaining_nodes++; 00464 } 00465 00466 node_edge = node_edge_predecessor; 00467 node_terminal = false; 00468 } 00469 00470 remaining_nodes++; // +1 for root node 00471 effective_node_count = remaining_nodes; 00472 DEBUG_OUT(Parent::verbosity > 1, "purged tree cache, nb of remaining nodes = " << remaining_nodes << std::endl); 00473 } 00474 00475 float init_threshold; 00476 float cur_threshold; 00477 float delta_threshold; 00478 bool solution_found; 00479 unsigned int effective_node_count; 00480 unsigned int nb_moves; 00481 float root_threshold; 00482 unsigned int tree_cache_size; 00483 bool unloop; 00484 float delta_init_threshold; 00485 }; 00486 00487 00488 00489 } // namespace ccsoft 00490 00491 #endif // __CC_FANO_DECODING_H__