Statistics
| Branch: | Tag: | Revision:

root / gnuradio-core / src / lib / filter / qa_gr_fir_ccf.cc @ 369834c8

History | View | Annotate | Download (4.5 kB)

1 5d69a524 jcorgan
/* -*- c++ -*- */
2 5d69a524 jcorgan
/*
3 5d69a524 jcorgan
 * Copyright 2002 Free Software Foundation, Inc.
4 5d69a524 jcorgan
 * 
5 5d69a524 jcorgan
 * This file is part of GNU Radio
6 5d69a524 jcorgan
 * 
7 5d69a524 jcorgan
 * GNU Radio is free software; you can redistribute it and/or modify
8 5d69a524 jcorgan
 * it under the terms of the GNU General Public License as published by
9 937b719d eb
 * the Free Software Foundation; either version 3, or (at your option)
10 5d69a524 jcorgan
 * any later version.
11 5d69a524 jcorgan
 * 
12 5d69a524 jcorgan
 * GNU Radio is distributed in the hope that it will be useful,
13 5d69a524 jcorgan
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 5d69a524 jcorgan
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 5d69a524 jcorgan
 * GNU General Public License for more details.
16 5d69a524 jcorgan
 * 
17 5d69a524 jcorgan
 * You should have received a copy of the GNU General Public License
18 5d69a524 jcorgan
 * along with GNU Radio; see the file COPYING.  If not, write to
19 86f5c924 eb
 * the Free Software Foundation, Inc., 51 Franklin Street,
20 86f5c924 eb
 * Boston, MA 02110-1301, USA.
21 5d69a524 jcorgan
 */
22 5d69a524 jcorgan
23 5d69a524 jcorgan
/*
24 5d69a524 jcorgan
 * FIXME.  This code is virtually identical to qa_gr_fir_?CC.cc
25 5d69a524 jcorgan
 *   Kludge up some kind of macro to handle the minor differences.
26 5d69a524 jcorgan
 */
27 5d69a524 jcorgan
28 5d69a524 jcorgan
#ifdef HAVE_CONFIG_H
29 5d69a524 jcorgan
#include <config.h>
30 5d69a524 jcorgan
#endif
31 5d69a524 jcorgan
32 5d69a524 jcorgan
#include <gr_types.h>
33 5d69a524 jcorgan
34 5d69a524 jcorgan
typedef gr_complex        i_type;
35 5d69a524 jcorgan
typedef gr_complex        o_type;
36 5d69a524 jcorgan
typedef float                tap_type;
37 5d69a524 jcorgan
typedef        gr_complex        acc_type;
38 5d69a524 jcorgan
39 5d69a524 jcorgan
40 5d69a524 jcorgan
#include <qa_gr_fir_ccf.h>
41 5d69a524 jcorgan
#include <gr_fir_ccf.h>
42 5d69a524 jcorgan
#include <gr_fir_util.h>
43 5d69a524 jcorgan
#include <string.h>
44 5d69a524 jcorgan
#include <iostream>
45 5d69a524 jcorgan
#include <cmath>
46 5d69a524 jcorgan
#include <gr_types.h>
47 5d69a524 jcorgan
#include <cppunit/TestAssert.h>
48 5d69a524 jcorgan
#include <random.h>
49 5d69a524 jcorgan
#include <malloc16.h>
50 38ea3a57 eb
#include <string.h>
51 5d69a524 jcorgan
52 5d69a524 jcorgan
using std::vector;
53 5d69a524 jcorgan
54 5d69a524 jcorgan
#define        ERR_DELTA        (1e-5)
55 5d69a524 jcorgan
56 5d69a524 jcorgan
#define        NELEM(x) (sizeof (x) / sizeof (x[0]))
57 5d69a524 jcorgan
58 5d69a524 jcorgan
//
59 5d69a524 jcorgan
// typedef for something logically "pointer to constructor".
60 5d69a524 jcorgan
// there may be a better way, please let me know...
61 5d69a524 jcorgan
//
62 5d69a524 jcorgan
typedef gr_fir_ccf* (*fir_maker_t)(const std::vector<tap_type> &taps);
63 5d69a524 jcorgan
64 5d69a524 jcorgan
static float
65 5d69a524 jcorgan
uniform ()
66 5d69a524 jcorgan
{
67 5d69a524 jcorgan
  return 2.0 * ((float) random () / RANDOM_MAX - 0.5);        // uniformly (-1, 1)
68 5d69a524 jcorgan
}
69 5d69a524 jcorgan
70 5d69a524 jcorgan
static void
71 5d69a524 jcorgan
random_floats (float *buf, unsigned n)
72 5d69a524 jcorgan
{
73 5d69a524 jcorgan
  for (unsigned i = 0; i < n; i++)
74 5d69a524 jcorgan
    buf[i] = (float) rint (uniform () * 32767);
75 5d69a524 jcorgan
}
76 5d69a524 jcorgan
77 5d69a524 jcorgan
static void
78 5d69a524 jcorgan
random_complex (gr_complex *buf, unsigned n)
79 5d69a524 jcorgan
{
80 5d69a524 jcorgan
  for (unsigned i = 0; i < n; i++){
81 5d69a524 jcorgan
    float re = rint (uniform () * 32767);
82 5d69a524 jcorgan
    float im = rint (uniform () * 32767);
83 5d69a524 jcorgan
    buf[i] = gr_complex (re, im);
84 5d69a524 jcorgan
  }
85 5d69a524 jcorgan
}
86 5d69a524 jcorgan
87 5d69a524 jcorgan
static o_type
88 5d69a524 jcorgan
ref_dotprod (const i_type input[], const tap_type taps[], int ntaps)
89 5d69a524 jcorgan
{
90 5d69a524 jcorgan
  acc_type        sum = 0;
91 5d69a524 jcorgan
  for (int i = 0; i < ntaps; i++)
92 5d69a524 jcorgan
    sum += input[i] * taps[ntaps - i - 1];
93 5d69a524 jcorgan
94 5d69a524 jcorgan
  return sum;
95 5d69a524 jcorgan
}
96 5d69a524 jcorgan
97 5d69a524 jcorgan
//
98 5d69a524 jcorgan
// Test for ntaps in [0,9], and input lengths in [0,17].
99 5d69a524 jcorgan
// This ensures that we are building the shifted taps correctly,
100 5d69a524 jcorgan
// and exercises all corner cases on input alignment and length.
101 5d69a524 jcorgan
//
102 5d69a524 jcorgan
103 5d69a524 jcorgan
static void
104 5d69a524 jcorgan
test_random_io (fir_maker_t maker)  
105 5d69a524 jcorgan
{
106 5d69a524 jcorgan
  const int        MAX_TAPS        = 9;
107 5d69a524 jcorgan
  const int        OUTPUT_LEN        = 17;
108 5d69a524 jcorgan
  const int        INPUT_LEN        = MAX_TAPS + OUTPUT_LEN;
109 5d69a524 jcorgan
110 5d69a524 jcorgan
  // Our SIMD ccc kernel requires that the complex input be 64-bit (8-byte) aligned.
111 5d69a524 jcorgan
  //i_type         input[INPUT_LEN];
112 5d69a524 jcorgan
  i_type       *input = (i_type *)malloc16Align(INPUT_LEN * sizeof(i_type));
113 5d69a524 jcorgan
  o_type         expected_output[OUTPUT_LEN];
114 5d69a524 jcorgan
  o_type         actual_output[OUTPUT_LEN];
115 5d69a524 jcorgan
  tap_type        taps[MAX_TAPS];
116 5d69a524 jcorgan
117 5d69a524 jcorgan
118 5d69a524 jcorgan
  srandom (0);        // we want reproducibility
119 5d69a524 jcorgan
120 5d69a524 jcorgan
  for (int n = 0; n <= MAX_TAPS; n++){
121 5d69a524 jcorgan
    for (int ol = 0; ol <= OUTPUT_LEN; ol++){
122 5d69a524 jcorgan
123 5d69a524 jcorgan
      // cerr << "@@@ n:ol " << n << ":" << ol << endl;
124 5d69a524 jcorgan
125 5d69a524 jcorgan
      // build random test case
126 5d69a524 jcorgan
      random_complex (input, INPUT_LEN);
127 5d69a524 jcorgan
      random_floats (taps, MAX_TAPS);
128 5d69a524 jcorgan
129 5d69a524 jcorgan
      // compute expected output values
130 5d69a524 jcorgan
      for (int o = 0; o < ol; o++){
131 5d69a524 jcorgan
        expected_output[o] = ref_dotprod (&input[o], taps, n);
132 5d69a524 jcorgan
      }
133 5d69a524 jcorgan
134 5d69a524 jcorgan
      // build filter
135 5d69a524 jcorgan
136 5d69a524 jcorgan
      vector<tap_type> f1_taps (&taps[0], &taps[n]);
137 5d69a524 jcorgan
      gr_fir_ccf *f1 = maker (f1_taps);
138 5d69a524 jcorgan
139 5d69a524 jcorgan
      // zero the output, then do the filtering
140 5d69a524 jcorgan
      memset (actual_output, 0, sizeof (actual_output));
141 5d69a524 jcorgan
      f1->filterN (actual_output, input, ol);
142 5d69a524 jcorgan
143 5d69a524 jcorgan
      // check results
144 5d69a524 jcorgan
      //
145 5d69a524 jcorgan
      // we use a sloppy error margin because on the x86 architecture,
146 5d69a524 jcorgan
      // our reference implementation is using 80 bit floating point
147 5d69a524 jcorgan
      // arithmetic, while the SSE version is using 32 bit float point
148 5d69a524 jcorgan
      // arithmetic.
149 5d69a524 jcorgan
      
150 5d69a524 jcorgan
      for (int o = 0; o < ol; o++){
151 0b0f2e10 eb
        CPPUNIT_ASSERT_COMPLEXES_EQUAL(expected_output[o], actual_output[o],
152 0b0f2e10 eb
                                       abs (expected_output[o]) * ERR_DELTA);
153 5d69a524 jcorgan
      }
154 5d69a524 jcorgan
155 5d69a524 jcorgan
      delete f1;
156 5d69a524 jcorgan
    }
157 5d69a524 jcorgan
  }
158 5d69a524 jcorgan
  free16Align(input);
159 5d69a524 jcorgan
}
160 5d69a524 jcorgan
161 5d69a524 jcorgan
162 5d69a524 jcorgan
static void
163 5d69a524 jcorgan
for_each (void (*f)(fir_maker_t))
164 5d69a524 jcorgan
{
165 5d69a524 jcorgan
  std::vector<gr_fir_ccf_info>                info;
166 5d69a524 jcorgan
  gr_fir_util::get_gr_fir_ccf_info (&info);        // get all known ccf implementations 
167 5d69a524 jcorgan
168 5d69a524 jcorgan
  for (std::vector<gr_fir_ccf_info>::iterator p = info.begin ();
169 5d69a524 jcorgan
       p != info.end ();
170 5d69a524 jcorgan
       ++p){
171 5d69a524 jcorgan
172 5d69a524 jcorgan
    std::cerr << " [" << p->name << "]";
173 5d69a524 jcorgan
    f (p->create);
174 5d69a524 jcorgan
  }
175 5d69a524 jcorgan
176 5d69a524 jcorgan
  std::cerr << std::endl;
177 5d69a524 jcorgan
}
178 5d69a524 jcorgan
179 5d69a524 jcorgan
180 5d69a524 jcorgan
void
181 5d69a524 jcorgan
qa_gr_fir_ccf::t1 ()
182 5d69a524 jcorgan
{
183 5d69a524 jcorgan
  for_each (test_random_io);
184 5d69a524 jcorgan
}