summaryrefslogtreecommitdiff
path: root/viterbi_generator/utils
diff options
context:
space:
mode:
Diffstat (limited to 'viterbi_generator/utils')
-rw-r--r--viterbi_generator/utils/lower_utils/equations_gen.m124
-rw-r--r--viterbi_generator/utils/lower_utils/generate_increment.m72
-rw-r--r--viterbi_generator/utils/lower_utils/lower_utils/complex_vect2number.m44
-rw-r--r--viterbi_generator/utils/lower_utils/lower_utils/generate_previous.m35
-rw-r--r--viterbi_generator/utils/lower_utils/lower_utils/make_symbols.m35
-rw-r--r--viterbi_generator/utils/viterbi_generator.m305
6 files changed, 615 insertions, 0 deletions
diff --git a/viterbi_generator/utils/lower_utils/equations_gen.m b/viterbi_generator/utils/lower_utils/equations_gen.m
new file mode 100644
index 0000000..af7d37e
--- /dev/null
+++ b/viterbi_generator/utils/lower_utils/equations_gen.m
@@ -0,0 +1,124 @@
+function [increment, pm_candidates_imag, pm_candidates_real]= equations_gen(Lh)
+
+ ###########################################################################
+ # Copyright (C) 2008 by Piotr Krysik #
+ # pkrysik@stud.elka.pw.edu.pl #
+ # #
+ # This program 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 of the License, or #
+ # (at your option) any later version. #
+ # #
+ # This program 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 this program; if not, write to the #
+ # Free Software Foundation, Inc., #
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+ ###########################################################################
+
+INCREMENT_NUM=2**(Lh-1);
+
+SYMBOLS = make_symbols(Lh);
+PREVIOUS = generate_previous(Lh);
+
+load tests/data/rhh.dat
+
+[INCREMENT NUMBERS] = generate_increment(SYMBOLS,PREVIOUS);
+
+function_real="real";
+function_imag="imag";
+sign="";
+fction="";
+equation_num="";
+increment = { };
+equation="";
+
+for equation_num=1:INCREMENT_NUM,
+ for part_num=1:Lh,
+ coefficient=INCREMENT(equation_num,part_num);
+ if(coefficient==1 || coefficient==-1),
+ fction=function_real;
+ else
+ fction=function_imag;
+ coefficient=coefficient*j;
+ end
+
+ if(coefficient==1 && part_num != 1),
+ sign="+";
+ elseif(coefficient==-1),
+ sign="-";
+ else
+ sign="";
+ end
+
+ equation = [equation " " sign "rhh[" int2str(part_num) "]." fction "()" ];
+ end
+
+ increment(equation_num) = ["increment[" int2str(equation_num-1) "] =" equation];
+ equation="";
+end
+
+
+BRANCH_NUM=2**(Lh+1);
+
+
+%make path metrics
+pm_candidates_real={};
+pm_candidates_imag={};
+for symbol_num=1:BRANCH_NUM,
+
+ inc1_num=NUMBERS(PREVIOUS(symbol_num,1),symbol_num);
+ inc2_num=NUMBERS(PREVIOUS(symbol_num,2),symbol_num);
+
+ symbol=SYMBOLS(symbol_num,1);
+
+ if(inc1_num<0)
+ inc1_sign="+";
+ inc1_num=-inc1_num;
+ else
+ inc1_sign="-";
+ end
+
+ if(inc2_num<0)
+ inc2_sign="+";
+ inc2_num=-inc2_num;
+ else
+ inc2_sign="-";
+ end
+
+ inc1_num=inc1_num-1;
+ inc2_num=inc2_num-1;
+
+ if(symbol==1 || symbol==-1),
+ fction=function_real;
+ else
+ fction=function_imag;
+ symbol=symbol*(-j);
+ end
+
+ if(symbol==1),
+ symbol_sign="+";
+ else
+ symbol_sign="-";
+ end
+
+ branch_metric1=[" " symbol_sign " input_symbol_" fction " " inc1_sign " increment[" int2str(inc1_num) "]" ];
+ branch_metric2=[" " symbol_sign " input_symbol_" fction " " inc2_sign " increment[" int2str(inc2_num) "]" ];
+
+ num = ceil((symbol_num)/2);
+ prev1_num = ceil((PREVIOUS(symbol_num,1))/2)-1;
+ prev2_num = ceil((PREVIOUS(symbol_num,2))/2)-1;
+
+ if(mod(symbol_num,2)==1),
+ pm_candidates_imag(num, 1)=[ "pm_candidate1 = old_path_metrics[" int2str(prev1_num) "]" branch_metric1 ];
+ pm_candidates_imag(num, 2)=[ "pm_candidate2 = old_path_metrics[" int2str(prev2_num) "]" branch_metric2 ];
+ else
+ pm_candidates_real(num, 1)=[ "pm_candidate1 = old_path_metrics[" int2str(prev1_num) "]" branch_metric1 ];
+ pm_candidates_real(num, 2)=[ "pm_candidate2 = old_path_metrics[" int2str(prev2_num) "]" branch_metric2 ];
+ end
+end
+
diff --git a/viterbi_generator/utils/lower_utils/generate_increment.m b/viterbi_generator/utils/lower_utils/generate_increment.m
new file mode 100644
index 0000000..9575796
--- /dev/null
+++ b/viterbi_generator/utils/lower_utils/generate_increment.m
@@ -0,0 +1,72 @@
+function [INCREMENT NUMBERS] = generate_increment(SYMBOLS,PREVIOUS)%,Rhh)
+
+ ###########################################################################
+ # Copyright (C) 2008 by Piotr Krysik #
+ # pkrysik@stud.elka.pw.edu.pl #
+ # #
+ # This program 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 of the License, or #
+ # (at your option) any later version. #
+ # #
+ # This program 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 this program; if not, write to the #
+ # Free Software Foundation, Inc., #
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+ ###########################################################################
+
+MSK_STATES_NUM=4; % 1,-1,j,-j
+[POSIBLE_SEQ_NUM,Lh]=size(SYMBOLS);
+INCREMENT_NUM=2**(Lh-1);
+%Lh - channel memory length
+%POSIBLE_SEQ_NUM - number of posible sequences of MSK symbols (1,-1,j,-j) for given Lh
+
+%INCREMENT=zeros(2,Lh,POSIBLE_SEQ_NUM/8);
+
+% Rhh IS STORED AS:
+% [ Rhh(1) Rhh(2) Rhh(3) ... Rhh(Lh) ]
+INCREMENT=zeros(INCREMENT_NUM, Lh);
+
+for n=1:POSIBLE_SEQ_NUM,
+ % ONLY TWO LEGAL PREVIOUS STATES EXIST, SO THE LOOP IS UNROLLED
+ m=PREVIOUS(n,1);
+ vector=[conj(SYMBOLS(n,1))* SYMBOLS(m,:)];
+ number=complex_vect2number(vector);
+ if(number>0)
+ INCREMENT(number,:)=vector;
+ end
+
+ NUMBERS(m,n)=number;
+
+ m=PREVIOUS(n,2);
+ vector=[conj(SYMBOLS(n,1))* SYMBOLS(m,:)];
+ number=complex_vect2number(vector);
+ if(number>0)
+ INCREMENT(number,:)=vector;
+ end
+ NUMBERS(m,n)=number;
+end
+
+%test_inc=zeros(2**(Lh+1),2**(Lh+1));
+%for n=1:2**(Lh+1),
+% for m=1:2**(Lh+1),
+% number=NUMBERS(m,n);
+
+% if(number!=0)
+% sign=1;
+% if(number<0),
+% sign=-1;
+% number=-number;
+% end
+% test_inc(m,n)=real(sign*INCREMENT(number,:)*Rhh(2:Lh+1).');
+% end
+% end
+%end
+%INCREMENT
+%test_inc
+%NUMBERS
diff --git a/viterbi_generator/utils/lower_utils/lower_utils/complex_vect2number.m b/viterbi_generator/utils/lower_utils/lower_utils/complex_vect2number.m
new file mode 100644
index 0000000..f0d6d25
--- /dev/null
+++ b/viterbi_generator/utils/lower_utils/lower_utils/complex_vect2number.m
@@ -0,0 +1,44 @@
+function [ number ] = complex_vect2number(vector)
+
+ ###########################################################################
+ # Copyright (C) 2008 by Piotr Krysik #
+ # pkrysik@stud.elka.pw.edu.pl #
+ # #
+ # This program 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 of the License, or #
+ # (at your option) any later version. #
+ # #
+ # This program 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 this program; if not, write to the #
+ # Free Software Foundation, Inc., #
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+ ###########################################################################
+
+% Change complex vector of values: 1,-1 or j,-j
+% into a integer number.
+
+ number=0;
+ [r,Lh] = size(vector);
+ for l=1:Lh,
+ position=2**(l-1);
+ if(vector(l)==1),
+ number=number+position*(1);
+ elseif(vector(l)==-1),
+ number=number+position*(-1);
+ elseif(vector(l)==-j),
+ number=number+position*(1);
+ elseif(vector(l)==j),
+ number=number+position*(-1);
+ end
+ end
+ if number < 0,
+ number=floor(number/2);
+ else
+ number=ceil(number/2);
+ end
diff --git a/viterbi_generator/utils/lower_utils/lower_utils/generate_previous.m b/viterbi_generator/utils/lower_utils/lower_utils/generate_previous.m
new file mode 100644
index 0000000..942c4dc
--- /dev/null
+++ b/viterbi_generator/utils/lower_utils/lower_utils/generate_previous.m
@@ -0,0 +1,35 @@
+function [ PREVIOUS ] = generate_previous(Lh)
+
+ ###########################################################################
+ # Copyright (C) 2008 by Piotr Krysik #
+ # pkrysik@stud.elka.pw.edu.pl #
+ # #
+ # This program 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 of the License, or #
+ # (at your option) any later version. #
+ # #
+ # This program 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 this program; if not, write to the #
+ # Free Software Foundation, Inc., #
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+ ###########################################################################
+
+SYMBOLS_NUM = 2**(Lh+1);
+n=1;
+for i=1:4:SYMBOLS_NUM,
+ PREVIOUS(i,1) = n+1;
+ PREVIOUS(i,2) = n+SYMBOLS_NUM/2+1;
+ PREVIOUS(i+1,1) = n;
+ PREVIOUS(i+1,2) = n+SYMBOLS_NUM/2;
+ PREVIOUS(i+2,1) = n+1;
+ PREVIOUS(i+2,2) = n+SYMBOLS_NUM/2+1;
+ PREVIOUS(i+3,1) = n;
+ PREVIOUS(i+3,2) = n+SYMBOLS_NUM/2;
+ n=n+2;
+end
diff --git a/viterbi_generator/utils/lower_utils/lower_utils/make_symbols.m b/viterbi_generator/utils/lower_utils/lower_utils/make_symbols.m
new file mode 100644
index 0000000..3849fbd
--- /dev/null
+++ b/viterbi_generator/utils/lower_utils/lower_utils/make_symbols.m
@@ -0,0 +1,35 @@
+function [ SYMBOLS ] = make_symbols(Lh)
+
+ ###########################################################################
+ # Copyright (C) 2008 by Piotr Krysik #
+ # pkrysik@stud.elka.pw.edu.pl #
+ # #
+ # This program 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 of the License, or #
+ # (at your option) any later version. #
+ # #
+ # This program 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 this program; if not, write to the #
+ # Free Software Foundation, Inc., #
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+ ###########################################################################
+
+BRANCH_NUM=2**(Lh+1);
+SYMBOLS=ones(BRANCH_NUM, Lh);
+
+for column=1:Lh,
+ for i=1:(2**column),
+ SYMBOLS(i:(2**(column+1)):BRANCH_NUM,column)=-1;
+ end
+
+end
+
+SYMBOLS(1:2:BRANCH_NUM, 1:2:Lh) = SYMBOLS(1:2:BRANCH_NUM, 1:2:Lh).*(-j);
+SYMBOLS(2:2:BRANCH_NUM, 2:2:Lh) = SYMBOLS(2:2:BRANCH_NUM, 2:2:Lh).*(-j);
+
diff --git a/viterbi_generator/utils/viterbi_generator.m b/viterbi_generator/utils/viterbi_generator.m
new file mode 100644
index 0000000..f9a9621
--- /dev/null
+++ b/viterbi_generator/utils/viterbi_generator.m
@@ -0,0 +1,305 @@
+function [viterbi_detector] = viterbi_generator(Lh, varargin)
+
+ ###########################################################################
+ # Copyright (C) 2008 by Piotr Krysik #
+ # pkrysik@stud.elka.pw.edu.pl #
+ # #
+ # This program 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 of the License, or #
+ # (at your option) any later version. #
+ # #
+ # This program 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 this program; if not, write to the #
+ # Free Software Foundation, Inc., #
+ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
+ ###########################################################################
+
+if(nargin!=1 && nargin !=3),
+ printf("Bad number of arguments in viterbi_generator(...)");
+ exit(1)
+elseif(nargin==1)
+ print_matrix_type="";
+ print_path_metrics="";
+elseif(nargin==3)
+ %additional parameters for test
+ print_matrix_type=varargin{1};
+ print_path_metrics=varargin{2};
+end
+
+INCREMENT_NUM=2**(Lh-1);
+BRANCH_NUM=2**(Lh+1);
+PATHS_NUM=2**(Lh);
+PREVIOUS = generate_previous(Lh);
+
+[increment, pm_candidates_imag, pm_candidates_real] = equations_gen(Lh);
+
+function_interface_comment="\
+/*\n\
+** viterbi_detector:\n\
+** This part does the detection of received sequnece.\n\
+** Employed algorithm is viterbi Maximum Likehood Sequence Estimation.\n\
+** At this moment it gives hard decisions on the output, but\n\
+** it was designed with soft decisions in mind.\n\
+**\n\
+** SYNTAX: void viterbi_detector(\n\
+** const gr_complex * input, \n\
+** unsigned int samples_num, \n\
+** gr_complex * rhh, \n\
+** unsigned int start_state, \n\
+** const unsigned int * stop_states, \n\
+** unsigned int stops_num, \n\
+** float * output)\n\
+**\n\
+** INPUT: input: Complex received signal afted matched filtering.\n\
+** samples_num: Number of samples in the input table.\n\
+** rhh: The autocorrelation of the estimated channel \n\
+** impulse response.\n\
+** start_state: Number of the start point. In GSM each burst \n\
+** starts with sequence of three bits (0,0,0) which \n\
+** indicates start point of the algorithm.\n\
+** stop_states: Table with numbers of possible stop states.\n\
+** stops_num: Number of possible stop states\n\
+** \n\
+**\n\
+** OUTPUT: output: Differentially decoded hard output of the algorithm: \n\
+** -1 for logical \"0\" and 1 for logical \"1\"\n\
+**\n\
+** SUB_FUNC: none\n\
+**\n\
+** TEST(S): Tested with real world normal burst.\n\
+*/\n\n";
+
+beginning=[ "\
+#include <gnuradio/gr_complex.h>\n\
+#define BURST_SIZE 148\n\
+#define PATHS_NUM " int2str(PATHS_NUM) "\n\
+\n\
+void viterbi_detector(const gr_complex * input, unsigned int samples_num, gr_complex * rhh, unsigned int start_state, const unsigned int * stop_states, unsigned int stops_num, float * output)\n\
+{\n\
+ float increment[" int2str(INCREMENT_NUM) "];\n\
+ float path_metrics1[" int2str(PATHS_NUM) "];\n\
+ float path_metrics2[" int2str(PATHS_NUM) "];\n\
+ float * new_path_metrics;\n\
+ float * old_path_metrics;\n\
+ float * tmp;\n\
+ float trans_table[BURST_SIZE][" int2str(PATHS_NUM) "];\n\
+ float pm_candidate1, pm_candidate2;\n\
+ bool real_imag;\n\
+ float input_symbol_real, input_symbol_imag;\n\
+ unsigned int i, sample_nr;\n\n" ];
+
+
+
+start_point_comment="\
+/*\n\
+* Setup first path metrics, so only state pointed by start_state is possible.\n\
+* Start_state metric is equal to zero, the rest is written with some very low value,\n\
+* which makes them practically impossible to occur.\n\
+*/\n";
+
+start_point=[ "\
+ for(i=0; i<PATHS_NUM; i++){\n\
+ path_metrics1[i]=(-10e30);\n\
+ }\n\
+ path_metrics1[start_state]=0;\n\n" ];
+
+
+
+increment_comment="\
+/*\n\
+* Compute Increment - a table of values which does not change for subsequent input samples.\n\
+* Increment is table of reference levels for computation of branch metrics:\n\
+* branch metric = (+/-)received_sample (+/-) reference_level\n\
+*/\n";
+
+increment_block="";
+for i=1:INCREMENT_NUM,
+ increment_block = [increment_block sprintf(" %s;\n",increment(i))];
+end
+
+
+
+path_metrics_comment="\n\n\
+/*\n\
+* Computation of path metrics and decisions (Add-Compare-Select).\n\
+* It's composed of two parts: one for odd input samples (imaginary numbers)\n\
+* and one for even samples (real numbers).\n\
+* Each part is composed of independent (parallelisable) statements like \n\
+* this one:\n\
+* pm_candidate1 = old_path_metrics[0] - input_symbol_real - increment[7];\n\
+* pm_candidate2 = old_path_metrics[8] - input_symbol_real + increment[0];\n\
+* if(pm_candidate1 > pm_candidate2){\n\
+* new_path_metrics[0] = pm_candidate1;\n\
+* trans_table[sample_nr][0] = -1.0;\n\
+* }\n\
+* else{\n\
+* new_path_metrics[0] = pm_candidate2;\n\
+* trans_table[sample_nr][0] = 1.0;\n\
+* }\n\
+* This is very good point for optimisations (SIMD or OpenMP) as it's most time \n\
+* consuming part of this function. \n\
+*/\n";
+
+path_metrics_block=" sample_nr=0;\n";
+
+path_metrics_block=[path_metrics_block " old_path_metrics=path_metrics1;\n"];
+path_metrics_block=[path_metrics_block " new_path_metrics=path_metrics2;\n"];
+
+path_metrics_block=[path_metrics_block "\
+ while(sample_nr<samples_num){\n\
+ //Processing imag states\n\
+ real_imag=1;\n\
+ input_symbol_imag = input[sample_nr].imag();\n"];
+
+
+ for i=1:PATHS_NUM,
+ path_metrics_block=[path_metrics_block sprintf("\n %s;\n %s;\n", pm_candidates_imag(i, 1), pm_candidates_imag(i, 2)) ];
+
+ path_metrics_block=[path_metrics_block "\
+ if(pm_candidate1 > pm_candidate2){\n\
+ new_path_metrics[" int2str(i-1) "] = pm_candidate1;\n\
+ trans_table[sample_nr][" int2str(i-1) "] = -1.0;\n\
+ }\n\
+ else{\n\
+ new_path_metrics[" int2str(i-1) "] = pm_candidate2;\n\
+ trans_table[sample_nr][" int2str(i-1) "] = 1.0;\n\
+ }\n"];
+ end
+
+ path_metrics_block=[path_metrics_block print_path_metrics];
+ %change new metrics into old metrics
+ path_metrics_block=[path_metrics_block " tmp=old_path_metrics;\n"];
+ path_metrics_block=[path_metrics_block " old_path_metrics=new_path_metrics;\n"];
+ path_metrics_block=[path_metrics_block " new_path_metrics=tmp;\n\n"];
+
+ path_metrics_block=[path_metrics_block " sample_nr++;\n"];
+ path_metrics_block=[path_metrics_block " if(sample_nr==samples_num)\n break;\n\n"];
+ path_metrics_block=[path_metrics_block " //Processing real states\n"];
+ path_metrics_block=[path_metrics_block " real_imag=0;\n"];
+ path_metrics_block=[path_metrics_block " input_symbol_real = input[sample_nr].real();\n"];
+ for i=1:PATHS_NUM,
+ path_metrics_block=[path_metrics_block sprintf("\n %s;\n %s;\n", pm_candidates_real(i, 1), pm_candidates_real(i, 2)) ];
+ path_metrics_block=[path_metrics_block "\
+ if(pm_candidate1 > pm_candidate2){\n\
+ new_path_metrics[" int2str(i-1) "] = pm_candidate1;\n\
+ trans_table[sample_nr][" int2str(i-1) "] = -1.0;\n\
+ }\n\
+ else{\n\
+ new_path_metrics[" int2str(i-1) "] = pm_candidate2;\n\
+ trans_table[sample_nr][" int2str(i-1) "] = 1.0;\n\
+ }\n"];
+ end
+ path_metrics_block=[path_metrics_block print_path_metrics];
+ %change new metrics into old metrics
+ path_metrics_block=[path_metrics_block " tmp=old_path_metrics;\n"];
+ path_metrics_block=[path_metrics_block " old_path_metrics=new_path_metrics;\n"];
+ path_metrics_block=[path_metrics_block " new_path_metrics=tmp;\n"];
+
+ path_metrics_block=[path_metrics_block "\n sample_nr++;\n"];
+
+path_metrics_block=[path_metrics_block " }\n\n"];
+
+
+
+find_best_stop_comment="\
+/*\n\
+* Find the best from the stop states by comparing their path metrics.\n\
+* Not every stop state is always possible, so we are searching in\n\
+* a subset of them.\n\
+*/\n";
+
+find_best_stop=[ " unsigned int best_stop_state;\n"];
+find_best_stop=[ find_best_stop " float stop_state_metric, max_stop_state_metric;\n" ];
+find_best_stop=[ find_best_stop " best_stop_state = stop_states[0];\n"];
+find_best_stop=[ find_best_stop " max_stop_state_metric = old_path_metrics[best_stop_state];\n"];
+find_best_stop=[ find_best_stop " for(i=1; i< stops_num; i++){\n"];
+find_best_stop=[ find_best_stop " stop_state_metric = old_path_metrics[stop_states[i]];\n"];
+find_best_stop=[ find_best_stop " if(stop_state_metric > max_stop_state_metric){\n"];
+find_best_stop=[ find_best_stop " max_stop_state_metric = stop_state_metric;\n"];
+find_best_stop=[ find_best_stop " best_stop_state = stop_states[i];\n"];
+find_best_stop=[ find_best_stop " }\n"];
+find_best_stop=[ find_best_stop " }\n\n"];
+
+
+
+parity_table_comment="\
+/*\n\
+* This table was generated with hope that it gives a litle speedup during\n\
+* traceback stage. \n\
+* Received bit is related to the number of state in the trellis.\n\
+* I've numbered states so their parity (number of ones) is related\n\
+* to a received bit. \n\
+*/\n";
+
+parity_table=[" static const unsigned int parity_table[PATHS_NUM] = { "];
+for i=1:PATHS_NUM/4,
+ parity_table=[ parity_table "0, 1, 1, 0, " ]; %int2str(even_parity(i-1))
+end
+parity_table=[ parity_table " };\n\n" ];
+
+
+
+prev_table_comment="\
+/*\n\
+* Table of previous states in the trellis diagram.\n\
+* For GMSK modulation every state has two previous states.\n\
+* Example:\n\
+* previous_state_nr1 = prev_table[current_state_nr][0]\n\
+* previous_state_nr2 = prev_table[current_state_nr][1]\n\
+*/\n";
+
+prev=ceil(PREVIOUS(1:2:2**(Lh+1),:)/2);
+prev_table=[" static const unsigned int prev_table[PATHS_NUM][2] = { "];
+for i=1:PATHS_NUM,
+ prev_table=[ prev_table "{" int2str(prev(i,1)-1) "," int2str(prev(i,2)-1) "}, " ];
+end
+prev_table=[ prev_table " };\n\n" ];
+
+
+
+traceback_comment="\
+/*\n\
+* Traceback and differential decoding of received sequence.\n\
+* Decisions stored in trans_table are used to restore best path in the trellis.\n\
+*/\n";
+
+traceback = [ " sample_nr=samples_num;\n"];
+traceback = [traceback " unsigned int state_nr=best_stop_state;\n"];
+traceback = [traceback " unsigned int decision;\n"];
+traceback = [traceback " bool out_bit=0;\n\n"];
+traceback = [traceback " while(sample_nr>0){\n" ];
+traceback = [traceback " sample_nr--;\n" ];
+traceback = [traceback " decision = (trans_table[sample_nr][state_nr]>0);\n\n" ];
+
+traceback = [traceback " if(decision != out_bit)\n"];
+traceback = [traceback " output[sample_nr]=-trans_table[sample_nr][state_nr];\n" ];
+traceback = [traceback " else\n" ];
+traceback = [traceback " output[sample_nr]=trans_table[sample_nr][state_nr];\n\n" ];
+
+traceback = [traceback " out_bit = out_bit ^ real_imag ^ parity_table[state_nr];\n" ];
+traceback = [traceback " state_nr = prev_table[state_nr][decision];\n" ];
+traceback = [traceback " real_imag = !real_imag;\n"];
+traceback = [traceback " }\n" ];
+
+
+
+end_of_viterbi_detector = [ "}\n" ];
+
+viterbi_detector=[function_interface_comment \
+ beginning \
+ start_point_comment start_point \
+ increment_comment increment_block \
+ path_metrics_comment print_matrix_type path_metrics_block \
+ find_best_stop_comment find_best_stop \
+ parity_table_comment parity_table \
+ prev_table_comment prev_table \
+ traceback_comment traceback \
+ end_of_viterbi_detector];
+
+
personal git repositories of Harald Welte. Your mileage may vary