Statistics
| Branch: | Tag: | Revision:

root / gnuradio-core / src / lib / filter / qa_gr_fir_scc.cc @ 100e6105

History | View | Annotate | Download (4.3 kB)

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
/*
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.
26
 */
27
28
#ifdef HAVE_CONFIG_H
29
#include <config.h>
30
#endif
31
32
#include <gr_types.h>
33
34
typedef short                i_type;
35
typedef gr_complex        o_type;
36
typedef gr_complex        tap_type;
37
typedef        gr_complex        acc_type;
38
39
40
#include <qa_gr_fir_scc.h>
41
#include <gr_fir_scc.h>
42
#include <gr_fir_util.h>
43
#include <string.h>
44
#include <iostream>
45
#include <cmath>
46
#include <gr_types.h>
47
#include <cppunit/TestAssert.h>
48
#include <random.h>
49
50
using std::vector;
51
52
#define        ERR_DELTA        (1e-5)
53
54
#define        NELEM(x) (sizeof (x) / sizeof (x[0]))
55
56
//
57
// typedef for something logically "pointer to constructor".
58
// there may be a better way, please let me know...
59
//
60
typedef gr_fir_scc* (*fir_maker_t)(const std::vector<tap_type> &taps);
61
62
63
static float
64
uniform ()
65
{
66
  return 2.0 * ((float) random () / RANDOM_MAX - 0.5);        // uniformly (-1, 1)
67
}
68
69
static void
70
random_input (i_type *buf, unsigned n)
71
{
72
  for (unsigned i = 0; i < n; i++)
73
    buf[i] = (i_type) rint (uniform () * 32767);
74
}
75
76
static void
77
random_complex (gr_complex *buf, unsigned n)
78
{
79
  for (unsigned i = 0; i < n; i++){
80
    float re = rint (uniform () * 32767);
81
    float im = rint (uniform () * 32767);
82
    buf[i] = gr_complex (re, im);
83
  }
84
}
85
86
static o_type
87
ref_dotprod (const i_type input[], const tap_type taps[], int ntaps)
88
{
89
  acc_type        sum = 0;
90
  for (int i = 0; i < ntaps; i++)
91
    sum += (float) input[i] * taps[ntaps - i - 1];
92
93
  return sum;
94
}
95
96
//
97
// Test for ntaps in [0,9], and input lengths in [0,17].
98
// This ensures that we are building the shifted taps correctly,
99
// and exercises all corner cases on input alignment and length.
100
//
101
102
static void
103
test_random_io (fir_maker_t maker)  
104
{
105
  const int        MAX_TAPS        = 9;
106
  const int        OUTPUT_LEN        = 17;
107
  const int        INPUT_LEN        = MAX_TAPS + OUTPUT_LEN;
108
109
  i_type         input[INPUT_LEN];
110
  o_type         expected_output[OUTPUT_LEN];
111
  o_type         actual_output[OUTPUT_LEN];
112
  tap_type        taps[MAX_TAPS];
113
114
115
  srandom (0);        // we want reproducibility
116
117
  for (int n = 0; n <= MAX_TAPS; n++){
118
    for (int ol = 0; ol <= OUTPUT_LEN; ol++){
119
120
      // cerr << "@@@ n:ol " << n << ":" << ol << endl;
121
122
      // build random test case
123
      random_input (input, INPUT_LEN);
124
      random_complex (taps, MAX_TAPS);
125
126
      // compute expected output values
127
      for (int o = 0; o < ol; o++){
128
        expected_output[o] = ref_dotprod (&input[o], taps, n);
129
      }
130
131
      // build filter
132
133
      vector<tap_type> f1_taps (&taps[0], &taps[n]);
134
      gr_fir_scc *f1 = maker (f1_taps);
135
136
      // zero the output, then do the filtering
137
      memset (actual_output, 0, sizeof (actual_output));
138
      f1->filterN (actual_output, input, ol);
139
140
      // check results
141
      //
142
      // we use a sloppy error margin because on the x86 architecture,
143
      // our reference implementation is using 80 bit floating point
144
      // arithmetic, while the SSE version is using 32 bit float point
145
      // arithmetic.
146
      
147
      for (int o = 0; o < ol; o++){
148
        CPPUNIT_ASSERT_COMPLEXES_EQUAL(expected_output[o],
149
                                       actual_output[o],
150
                                       abs (expected_output[o]) * ERR_DELTA);
151
      }
152
153
      delete f1;
154
    }
155
  }
156
}
157
158
static void
159
for_each (void (*f)(fir_maker_t))
160
{
161
  std::vector<gr_fir_scc_info>                info;
162
  gr_fir_util::get_gr_fir_scc_info (&info);        // get all known scc implementations 
163
164
  for (std::vector<gr_fir_scc_info>::iterator p = info.begin ();
165
       p != info.end ();
166
       ++p){
167
168
    std::cerr << " [" << p->name << "]";
169
    f (p->create);
170
  }
171
172
  std::cerr << std::endl;
173
}
174
175
void
176
qa_gr_fir_scc::t1 ()
177
{
178
  for_each (test_random_io);
179
}