3 * Copyright 2008 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 along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "qa_gcp_fft_1d_r2.h"
23 #include <cppunit/TestAssert.h>
24 #include <gcp_fft_1d_r2.h>
27 #include <stdlib.h> // random, posix_memalign
30 typedef boost::shared_ptr<void> void_sptr;
32 // handle to embedded SPU executable
33 extern spe_program_handle_t gcell_all;
36 * Return pointer to cache-aligned chunk of storage of size size bytes.
37 * Throw if can't allocate memory. The storage should be freed
38 * with "free" when done. The memory is initialized to zero.
41 aligned_alloc(size_t size, size_t alignment = 128)
44 if (posix_memalign(&p, alignment, size) != 0){
45 perror("posix_memalign");
46 throw std::runtime_error("memory");
48 memset(p, 0, size); // zero the memory
54 void operator()(void *p) {
59 static boost::shared_ptr<void>
60 aligned_alloc_sptr(size_t size, size_t alignment = 128)
62 return boost::shared_ptr<void>(aligned_alloc(size, alignment), free_deleter());
67 qa_gcp_fft_1d_r2::t1()
70 opts.program_handle = gc_program_handle_from_address(&gcell_all);
72 gc_job_manager_sptr mgr = gc_make_job_manager(&opts);
75 for (int log2_fft_size = 5; log2_fft_size <= 12; log2_fft_size++){
76 test(mgr, log2_fft_size, true);
85 qa_gcp_fft_1d_r2::t2()
88 opts.program_handle = gc_program_handle_from_address(&gcell_all);
90 gc_job_manager_sptr mgr = gc_make_job_manager(&opts);
93 for (int log2_fft_size = 5; log2_fft_size <= 12; log2_fft_size++){
94 test(mgr, log2_fft_size, false);
102 qa_gcp_fft_1d_r2::t3()
107 qa_gcp_fft_1d_r2::t4()
112 abs_diff(std::complex<float> x, std::complex<float> y)
114 return std::max(std::abs(x.real()-y.real()),
115 std::abs(x.imag()-y.imag()));
119 float_abs_rel_error(float ref, float actual)
121 float delta = ref - actual;
122 if (std::abs(ref) < 1e-18)
124 return std::abs(delta/ref);
128 abs_rel_error(std::complex<float> ref, std::complex<float> actual)
130 return std::max(float_abs_rel_error(ref.real(), actual.real()),
131 float_abs_rel_error(ref.imag(), actual.imag()));
135 qa_gcp_fft_1d_r2::test(gc_job_manager_sptr mgr, int log2_fft_size, bool forward)
137 int fft_size = 1 << log2_fft_size;
139 // allocate aligned buffers with boost shared_ptr's
140 void_sptr fftw_in_void = aligned_alloc_sptr(fft_size * sizeof(std::complex<float>), 128);
141 void_sptr fftw_out_void = aligned_alloc_sptr(fft_size * sizeof(std::complex<float>), 128);
142 void_sptr cell_in_void = aligned_alloc_sptr(fft_size * sizeof(std::complex<float>), 128);
143 void_sptr cell_out_void = aligned_alloc_sptr(fft_size * sizeof(std::complex<float>), 128);
144 void_sptr cell_twiddle_void = aligned_alloc_sptr(fft_size/4 * sizeof(std::complex<float>), 128);
146 // cast them to the type we really want
147 std::complex<float> *fftw_in = (std::complex<float> *) fftw_in_void.get();
148 std::complex<float> *fftw_out = (std::complex<float> *) fftw_out_void.get();
149 std::complex<float> *cell_in = (std::complex<float> *) cell_in_void.get();
150 std::complex<float> *cell_out = (std::complex<float> *) cell_out_void.get();
151 std::complex<float> *cell_twiddle = (std::complex<float> *) cell_twiddle_void.get();
154 gcp_fft_1d_r2_forward_twiddle(log2_fft_size, cell_twiddle);
156 gcp_fft_1d_r2_reverse_twiddle(log2_fft_size, cell_twiddle);
158 srandom(1); // we want reproducibility
160 // initialize the input buffers
161 for (int i = 0; i < fft_size; i++){
162 std::complex<float> t((float) (random() & 0xfffff), (float) (random() & 0xfffff));
167 // ------------------------------------------------------------------------
168 // compute the reference answer
169 fftwf_plan plan = fftwf_plan_dft_1d (fft_size,
170 reinterpret_cast<fftwf_complex *>(fftw_in),
171 reinterpret_cast<fftwf_complex *>(fftw_out),
172 forward ? FFTW_FORWARD : FFTW_BACKWARD,
175 fprintf(stderr, "qa_gcp_fft_1d_r2: error creating FFTW plan\n");
176 throw std::runtime_error ("fftwf_plan_dft_r2c_1d failed");
180 fftwf_destroy_plan(plan);
182 // ------------------------------------------------------------------------
183 // compute the answer on the cell
184 gc_job_desc *jd = gcp_fft_1d_r2_submit(mgr, log2_fft_size, forward,
185 cell_out, cell_in, cell_twiddle);
186 if (!mgr->wait_job(jd)){
187 fprintf(stderr, "wait_job failed: %s\n", gc_job_status_string(jd->status).c_str());
188 mgr->free_job_desc(jd);
191 mgr->free_job_desc(jd);
193 // ------------------------------------------------------------------------
194 // compute the maximum of the relative error
196 for (int i = 0; i < fft_size; i++){
197 max_rel = std::max(max_rel, abs_rel_error(fftw_out[i], cell_out[i]));
199 printf("(%16.3f, %16.3fj) (%16.3f, %16.3fj) (%16.3f, %16.3fj)\n",
200 fftw_out[i].real(), fftw_out[i].imag(),
201 cell_out[i].real(), cell_out[i].imag(),
202 fftw_out[i].real() - cell_out[i].real(),
203 fftw_out[i].imag() - cell_out[i].imag());
206 fprintf(stdout, "%s fft_size = %4d max_rel_error = %e\n",
207 forward ? "fwd" : "rev", fft_size, max_rel);
209 // CPPUNIT_ASSERT(max_rel <= 1e-4);