3 * Copyright 2002 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
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)
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.
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.
27 #include <qa_gr_fir_fff.h>
28 #include <gr_fir_fff.h>
29 #include <gr_fir_util.h>
33 #include <cppunit/TestAssert.h>
40 typedef float tap_type;
41 typedef float acc_type;
43 #define ERR_DELTA (1e-6)
45 #define NELEM(x) (sizeof (x) / sizeof (x[0]))
49 // typedef for something logically "pointer to constructor".
50 // there may be a better way, please let me know...
52 typedef gr_fir_fff* (*fir_maker_t)(const std::vector<tap_type> &taps);
55 // ----------------------------------------------------------------
57 const static i_type input_1[] = {
58 234, -4, 23, -56, 45, 98, -23, -7
61 const static tap_type taps_1a[] = {
65 const static o_type expected_1a[] = {
66 -702, 12, -69, 168, -135, -294, 69, 21
69 const static tap_type taps_1b[] = {
73 const static o_type expected_1b[] = {
74 1186, -112, 339, -460, -167, 582, -87
77 // ----------------------------------------------------------------
80 test_known_io (fir_maker_t maker)
82 vector<tap_type> t1a (&taps_1a[0], &taps_1a[NELEM (taps_1a)]);
83 vector<tap_type> t1b (&taps_1b[0], &taps_1b[NELEM (taps_1b)]);
85 gr_fir_fff *f1 = maker (t1a); // create filter
86 CPPUNIT_ASSERT_EQUAL ((unsigned) 1, f1->ntaps ()); // check ntaps
88 // check filter output
89 int n = NELEM (input_1) - f1->ntaps () + 1;
90 for (int i = 0; i < n; i++)
91 CPPUNIT_ASSERT_DOUBLES_EQUAL (expected_1a[i], f1->filter (&input_1[i]), ERR_DELTA);
93 f1->set_taps (t1b); // set new taps
94 CPPUNIT_ASSERT_EQUAL ((unsigned) 2, f1->ntaps ()); // check ntaps
96 // check filter output
97 n = NELEM (input_1) - f1->ntaps () + 1;
98 for (int i = 0; i < n; i++)
99 CPPUNIT_ASSERT_DOUBLES_EQUAL (expected_1b[i], f1->filter (&input_1[i]), ERR_DELTA);
101 // test filterN interface
103 o_type output[NELEM (expected_1b)];
104 memset (output, 0, sizeof (output));
106 f1->filterN (output, input_1, n);
107 for (int i = 0; i < n; i++)
108 CPPUNIT_ASSERT_DOUBLES_EQUAL (expected_1b[i], output[i], ERR_DELTA);
114 // Test for ntaps in [0,9], and input lengths in [0,17].
115 // This ensures that we are building the shifted taps correctly,
116 // and exercises all corner cases on input alignment and length.
122 return 2.0 * ((float) random () / RANDOM_MAX - 0.5); // uniformly (-1, 1)
126 random_floats (float *buf, unsigned n)
128 for (unsigned i = 0; i < n; i++)
129 buf[i] = rint (uniform () * 32768);
133 ref_dotprod (const i_type input[], const tap_type taps[], int ntaps)
136 for (int i = 0; i < ntaps; i++)
137 sum += input[i] * taps[ntaps - i - 1];
143 test_random_io (fir_maker_t maker)
145 const int MAX_TAPS = 9;
146 const int OUTPUT_LEN = 17;
147 const int INPUT_LEN = MAX_TAPS + OUTPUT_LEN;
149 i_type input[INPUT_LEN];
150 o_type expected_output[OUTPUT_LEN];
151 o_type actual_output[OUTPUT_LEN];
152 tap_type taps[MAX_TAPS];
155 srandom (0); // we want reproducibility
157 for (int n = 0; n <= MAX_TAPS; n++){
158 for (int ol = 0; ol <= OUTPUT_LEN; ol++){
160 // cerr << "@@@ n:ol " << n << ":" << ol << endl;
162 // build random test case
163 random_floats (input, INPUT_LEN);
164 random_floats (taps, MAX_TAPS);
166 // compute expected output values
167 for (int o = 0; o < ol; o++){
168 expected_output[o] = ref_dotprod (&input[o], taps, n);
173 vector<tap_type> f1_taps (&taps[0], &taps[n]);
174 gr_fir_fff *f1 = maker (f1_taps);
176 // zero the output, then do the filtering
177 memset (actual_output, 0, sizeof (actual_output));
178 f1->filterN (actual_output, input, ol);
182 // we use a sloppy error margin because on the x86 architecture,
183 // our reference implementation is using 80 bit floating point
184 // arithmetic, while the SSE version is using 32 bit float point
187 for (int o = 0; o < ol; o++){
188 CPPUNIT_ASSERT_DOUBLES_EQUAL (expected_output[o], actual_output[o],
189 fabs (expected_output[o]) * 1e-4);
199 for_each (void (*f)(fir_maker_t))
201 std::vector<gr_fir_fff_info> info;
202 gr_fir_util::get_gr_fir_fff_info (&info); // get all known fff implementations
204 for (std::vector<gr_fir_fff_info>::iterator p = info.begin ();
208 std::cerr << " [" << p->name << "]";
212 std::cerr << std::endl;
218 for_each (test_known_io);
224 for_each (test_random_io);