3 * Copyright 2002,2010 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.
24 * FIXME. This code is virtually identical to qa_gr_fir_?CC.cc
25 * Kludge up some kind of macro to handle the minor differences.
35 typedef gr_complex o_type;
36 typedef gr_complex tap_type;
37 typedef gr_complex acc_type;
40 #include <qa_gr_fir_fcc.h>
41 #include <gr_fir_fcc.h>
42 #include <gr_fir_util.h>
47 #include <cppunit/TestAssert.h>
53 #define ERR_DELTA (1e-5)
55 #define NELEM(x) (sizeof (x) / sizeof (x[0]))
59 // typedef for something logically "pointer to constructor".
60 // there may be a better way, please let me know...
62 typedef gr_fir_fcc* (*fir_maker_t)(const std::vector<tap_type> &taps);
68 return 2.0 * ((float) random () / RANDOM_MAX - 0.5); // uniformly (-1, 1)
72 random_input (i_type *buf, unsigned n)
74 for (unsigned i = 0; i < n; i++)
75 buf[i] = (i_type) rint (uniform () * 32767);
79 random_complex (gr_complex *buf, unsigned n)
81 for (unsigned i = 0; i < n; i++){
82 float re = rint (uniform () * 32767);
83 float im = rint (uniform () * 32767);
84 buf[i] = gr_complex (re, im);
89 ref_dotprod (const i_type input[], const tap_type taps[], int ntaps)
92 for (int i = 0; i < ntaps; i++)
93 sum += input[i] * taps[ntaps - i - 1];
99 // Test for ntaps in [0,9], and input lengths in [0,17].
100 // This ensures that we are building the shifted taps correctly,
101 // and exercises all corner cases on input alignment and length.
105 test_random_io (fir_maker_t maker)
107 const int MAX_TAPS = 9;
108 const int OUTPUT_LEN = 17;
109 const int INPUT_LEN = MAX_TAPS + OUTPUT_LEN;
111 i_type input_raw[INPUT_LEN + 4*16/sizeof(i_type)];
112 CPPUNIT_ASSERT(((intptr_t) input_raw & 0x3) == 0);
113 memset(input_raw, 0, sizeof(input_raw));
114 i_type *input = &input_raw[2*16/sizeof(i_type)];
116 o_type expected_output[OUTPUT_LEN];
117 o_type actual_output[OUTPUT_LEN];
118 tap_type taps[MAX_TAPS];
121 srandom (0); // we want reproducibility
123 for (int n = 0; n <= MAX_TAPS; n++){
124 for (int ol = 0; ol <= OUTPUT_LEN; ol++){
126 // cerr << "@@@ n:ol " << n << ":" << ol << endl;
128 // build random test case
129 random_input (input, INPUT_LEN);
130 random_complex (taps, MAX_TAPS);
132 // compute expected output values
133 for (int o = 0; o < ol; o++){
134 expected_output[o] = ref_dotprod (&input[o], taps, n);
139 vector<tap_type> f1_taps (&taps[0], &taps[n]);
140 gr_fir_fcc *f1 = maker (f1_taps);
142 // zero the output, then do the filtering
143 memset (actual_output, 0, sizeof (actual_output));
144 f1->filterN (actual_output, input, ol);
148 // we use a sloppy error margin because on the x86 architecture,
149 // our reference implementation is using 80 bit floating point
150 // arithmetic, while the SSE version is using 32 bit float point
153 for (int o = 0; o < ol; o++){
154 CPPUNIT_ASSERT_COMPLEXES_EQUAL(expected_output[o],
156 abs (expected_output[o]) * ERR_DELTA);
165 for_each (void (*f)(fir_maker_t))
167 std::vector<gr_fir_fcc_info> info;
168 gr_fir_util::get_gr_fir_fcc_info (&info); // get all known fcc implementations
170 for (std::vector<gr_fir_fcc_info>::iterator p = info.begin ();
174 std::cerr << " [" << p->name << "]";
178 std::cerr << std::endl;
184 for_each (test_random_io);