Merge commit 'v3.3.0' into upstream
[debian/gnuradio] / gr-atsc / src / lib / qa_atsci_single_viterbi.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2002 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <cppunit/TestAssert.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <atsci_single_viterbi.h>
31 #include <qa_atsci_single_viterbi.h>
32 #include <random.h>
33 #include <string.h>
34
35
36 static const int NTRIALS     =   50;
37 static const int MAXERRORS   =   10;
38 static const int NN          =  200;
39
40 static const int MAXDIBIT    = 3;
41
42 void
43 qa_atsci_single_viterbi::encode_block (unsigned char *out, unsigned char *in, 
44                                       unsigned int n)
45 {
46   for (unsigned int i = 0; i < n; i++) {
47     out[i] = encoder.encode(in[i]);
48   }
49 }
50
51
52 void
53 qa_atsci_single_viterbi::decode_block (unsigned char *out, unsigned char *in, 
54                                       unsigned int n, float noise_factor)
55 {
56   for (unsigned int i = 0; i < n; i++) {
57     out[i] = decoder.decode((2*in[i]-7) + noise () * noise_factor);
58   }
59 }
60
61 float
62 qa_atsci_single_viterbi::noise ()
63 {
64   return 2.0 * ((float) random () / RANDOM_MAX - 0.5);  // uniformly (-1, 1)
65 }
66
67 void
68 qa_atsci_single_viterbi::t0 ()
69 {
70   int                     blocklen = NN;
71   unsigned char           in[blocklen];
72   unsigned char           enc[blocklen];
73   unsigned char           out[blocklen];
74   int                     decoder_errors = 0;
75   int                     delay = decoder.delay ();
76   int                     i;
77
78   // printf ("  Delay is %d.\n", delay);
79   
80   srandom (27);         // reproducable sequence of "random" values
81   
82   for (int nt = 0; nt < NTRIALS; nt++){
83
84     // load block with random data and encode
85
86     for (i = 0; i < (blocklen-delay); i++)
87       in[i] = random () & MAXDIBIT;
88     for (     ; i < blocklen; i++)
89       in[i] = 0;                /* To empty the delay buffers */
90
91     encoder.reset ();
92     encode_block (enc, in, blocklen);
93
94     decoder.reset ();
95
96     // decode the block
97     decode_block (out, enc, blocklen, 1.0);
98
99     // int offset = delay/4;
100     int offset = 2;
101     bool differs = (memcmp (in+offset,
102                             out+delay+offset, blocklen-(delay+offset)));
103
104     // initial values after reset are 0
105     for (i = 0; i < delay; i++){
106       if (out[i] != 0)
107         printf ("  initial output at %i is %X, not 0\n",
108                 i, out[i]);
109     }
110
111     if (differs){
112       printf ("  incorrect data\n");
113
114       printf ("\n  Erroneous result dibits:");
115       for (int erri = 0; erri < (NN-delay); erri++) {
116         if (in[erri] != out[erri+delay])
117           printf (" %d", erri);
118       }
119       printf ("\n  In:  ");
120       for (int erri = 0; erri < (NN-delay); erri++) {
121         printf (" %d", in[erri]);
122       }
123       printf ("\n  Out: ");
124       for (int erri = 0; erri < (NN-delay); erri++) {
125         printf (" %d", out[erri+delay]);
126       }
127       printf ("\n  Errs:");
128       for (int erri = 0; erri < (NN-delay); erri++) {
129         printf (" %c", (in[erri] != out[erri+delay])? '*': ' ');
130       }
131       printf ("\n    THIS IS A REAL PROBLEM.\n");
132       decoder_errors++;
133     }
134   }
135
136   printf ("  Summary: %d decoder errors out of %d trials.\n",
137           decoder_errors, NTRIALS);
138
139   CPPUNIT_ASSERT (decoder_errors == 0);
140 }
141
142 void
143 qa_atsci_single_viterbi::t1 ()
144 {
145   int                     blocklen = NN;
146   unsigned char           in[blocklen];
147   unsigned char           enc[blocklen];
148   unsigned char           out[blocklen];
149   int                     errlocs[NN];
150   int                     errval;
151   int                     errloc;
152   int                     decoder_errors = 0;
153   int                     delay = decoder.delay ();
154   int                     i;
155
156   // printf ("  Delay is %d.\n", delay);
157   
158   srandom (1);          // reproducable sequence of "random" values
159   
160   for (int nt = 0; nt < NTRIALS; nt++){
161
162     // test up to the error correction capacity of the code
163     for (int errors = 0; errors <= MAXERRORS; errors++){
164
165       // load block with random data and encode
166
167       for (i = 0; i < (blocklen-delay); i++)
168         in[i] = random () & MAXDIBIT;
169       for (     ; i < blocklen; i++)
170         in[i] = 0;              /* To empty the delay buffers */
171
172       encoder.reset ();
173       encode_block (enc, in, blocklen);
174
175       // Now generate 0 to N errors in the encoded symbols.
176       //
177       //  If we restrict ourselves to damaging the low-order bit,
178       //  our decoder finds and fixes the vast majority of errors.
179       //
180       //  If we munge any or all of the three bits of the symbol,
181       //  our decoder frequently gets the wrong data even with a single
182       //  error.
183       //  
184       //  Let's see what it can do with just the two low-order bits.
185       //
186       // ALSO:  Don't let any error be within 12 spots of another
187       //  error.  This simulates the muxed behavior.
188
189       memset (errlocs, 0, sizeof (errlocs));
190
191       for (int j = 0; j < errors; j++){
192
193         do {
194           // errval = random () & 3;  // FIXME:  1;   // FIXME: MAXSYM;
195           errval = random () & 1;  // FIXME:  1;   // FIXME: MAXSYM;
196         } while (errval == 0);  // error value must be non-zero
197
198         // Don't insert errors in the first delay slot, since we
199         // don't have valid history to correct them.  Also, don't
200         // insert burst errors (adjacent errors), or errors within 2,
201         // since we can't reliably correct them.  Also we must not choose 
202         // the same location twice when inserting an error.
203
204         do {
205           errloc = random () % NN;
206         } while (errloc < delay || errlocs[errloc] != 0
207                  || (errloc > 0 && errlocs[errloc-1] != 0)
208                  || (errloc > 1 && errlocs[errloc-2] != 0)
209                  || (errloc < (NN-1) && errlocs[errloc+1] != 0)
210                  || (errloc < (NN-2) && errlocs[errloc+2] != 0));
211
212         errlocs[errloc] = 1;
213
214         enc[errloc] ^= errval;          // cause the error
215       }
216
217       // decode the errored block
218       decoder.reset ();
219       decode_block (out, enc, blocklen, 0.5);
220
221       // int offset = delay/4;
222       int offset = 2;
223       bool differs = (memcmp (in+offset,
224                               out+delay+offset, blocklen-(delay+offset)));
225
226       // initial values after reset are 0
227       for (i = 0; i < delay; i++){
228         if (out[i] != 0)
229           printf ("  initial output at %i is %X, not 0\n",
230                   i, out[i]);
231       }
232
233       if (differs){
234         printf ("  %2d errors introduced, %scorrect data\n",
235                  errors, differs? "in": "");
236
237         // FIXME, should we be able to tell how many errs too?
238         if (differs) {
239           const int ERRTOL = 12;                /* Or relate to delay? */
240           int shouldfix = 1;
241           int lasti = -ERRTOL;
242
243           printf (  "  Inserted errors:        ");
244           for (int erri = 0; erri < NN; erri++) {
245             if (errlocs[erri]) {
246               printf (" %d", erri);
247               // if (erri < lasti+ERRTOL)
248               //   shouldfix = 0;
249               lasti = erri;
250             }
251           }
252           printf ("\n  Erroneous result dibits:");
253           for (int erri = 0; erri < (NN-delay); erri++) {
254             if (in[erri] != out[erri+delay])
255               printf (" %d", erri);
256           }
257           printf ("\n  In:  ");
258           for (int erri = 0; erri < (NN-delay); erri++) {
259               printf (" %d", in[erri]);
260           }
261           printf ("\n  Out: ");
262           for (int erri = 0; erri < (NN-delay); erri++) {
263               printf (" %d", out[erri+delay]);
264           }
265           printf ("\n  Errs:");
266           for (int erri = 0; erri < (NN-delay); erri++) {
267             printf (" %c", (in[erri] != out[erri+delay])? '*': ' ');
268           }
269           if (shouldfix)
270             printf ("\n    THIS IS A REAL PROBLEM.\n");
271           else
272             printf ("\n    BUT THAT'S OK since errors are too close.\n");
273           if (shouldfix)
274             decoder_errors++;
275         }
276       }
277     }
278   }
279
280   printf ("  Summary: %d decoder errors out of %d trials.\n",
281           decoder_errors, (MAXERRORS*NTRIALS));
282
283   CPPUNIT_ASSERT (decoder_errors <= (MAXERRORS*NTRIALS) * .1);
284 }