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