4b781696d4b13098137abb33342b87cb8a3a59a9
[debian/gnuradio] / gr-gcell / src / gcell_fft_vcc.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2004,2007,2008 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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <gcell_fft_vcc.h>
28 #include <gr_io_signature.h>
29 #include <gc_job_manager.h>
30 #include <gc_aligned_alloc.h>
31 #include <gcp_fft_1d_r2.h>
32 #include <math.h>
33 #include <assert.h>
34 #include <stdexcept>
35
36
37 #define MIN_FFT_SIZE      32
38 #define MAX_FFT_SIZE    4096
39
40 inline static bool
41 is_power_of_2(int x)
42 {
43   return x != 0 && (x & (x-1)) == 0;
44 }
45
46 static int 
47 log2(int x)     // x is an exact power of 2
48 {
49   for (int i = 0; i < 32; i++)
50     if (x == (1 << i))
51       return i;
52
53   assert(0);
54 }
55
56 #if 0
57 gr_fft_vcc_sptr
58 gcell_make_fft_vcc(int fft_size, bool forward, const std::vector<float> &window, bool shift)
59 {
60   // If it doesn't meet our constraints, use standard implemenation
61   if (fft_size < MIN_FFT_SIZE || fft_size > MAX_FFT_SIZE
62       || !is_power_of_2(fft_size)
63       || (window.size() != 0 && fft_size > MAX_FFT_SIZE/2))
64     return gr_make_fft_vcc(fft_size, forward, window, shift);
65   else
66     return gr_fft_vcc_sptr (new gcell_fft_vcc(fft_size, forward, window, shift));
67 }
68 #else
69
70 gcell_fft_vcc_sptr
71 gcell_make_fft_vcc(int fft_size, bool forward, const std::vector<float> &window, bool shift)
72 {
73   return gcell_fft_vcc_sptr (new gcell_fft_vcc(fft_size, forward, window, shift));
74 }
75
76 #endif
77
78 gcell_fft_vcc::gcell_fft_vcc (int fft_size, bool forward,
79                               const std::vector<float> &window, bool shift)
80   : gr_fft_vcc("gcell_fft_vcc", fft_size, forward, window, shift)
81 {
82   if (fft_size < MIN_FFT_SIZE || fft_size > MAX_FFT_SIZE || !is_power_of_2(fft_size)){
83     throw std::invalid_argument("fft_size");
84   }
85
86   if (window.size() != 0 && fft_size > MAX_FFT_SIZE/2){
87     throw std::invalid_argument("fft_size too big to use window");
88   }
89
90   d_log2_fft_size = log2(fft_size);
91   d_mgr = gc_job_manager::singleton();          // grab the singleton job manager
92   d_twiddle_boost = gc_aligned_alloc_sptr(sizeof(std::complex<float>) * fft_size/4, 128);
93   d_twiddle = (std::complex<float>*) d_twiddle_boost.get();
94   gcp_fft_1d_r2_twiddle(d_log2_fft_size, d_twiddle);
95 }
96
97 gcell_fft_vcc::~gcell_fft_vcc ()
98 {
99 }
100
101 int
102 gcell_fft_vcc::work(int noutput_items,
103                     gr_vector_const_void_star &input_items,
104                     gr_vector_void_star &output_items)
105 {
106   const gr_complex *in = (const gr_complex *) input_items[0];
107   gr_complex *out = (gr_complex *) output_items[0];
108
109   // unsigned int input_data_size = input_signature()->sizeof_stream_item(0);
110   // unsigned int output_data_size = output_signature()->sizeof_stream_item(0);
111
112   float window_buf[MAX_FFT_SIZE/2] __attribute__((aligned (16)));
113   float *window = 0;
114   
115   // If we've got a window, ensure it's 16-byte aligned
116   // FIXME move this to set_window
117   if (d_window.size()){
118     if ((((intptr_t)&d_window[0]) & 0xf) == 0)
119       window = &d_window[0];            // OK as is
120     else {
121       window = window_buf;              // copy to aligned buffer
122       memcpy(window, &d_window[0], sizeof(float) * d_window.size());
123     }
124   }
125
126   std::vector<gc_job_desc_sptr> jd_sptr(noutput_items);
127   gc_job_desc *jd[noutput_items];
128   bool done[noutput_items];
129   
130   // submit noutput_items jobs in parallel
131
132   for (int i = 0; i < noutput_items; i++){
133     jd_sptr[i] = gcp_fft_1d_r2_submit(d_mgr, d_log2_fft_size,
134                                       d_forward, d_shift,
135                                       &out[i * d_fft_size],
136                                       &in[i * d_fft_size],
137                                       d_twiddle,
138                                       window);
139     jd[i] = jd_sptr[i].get();
140   }
141
142   int n = d_mgr->wait_jobs(noutput_items, jd, done, GC_WAIT_ALL);
143   if (n != noutput_items){
144     fprintf(stderr, "gcell_fft_vcc: wait_jobs returned %d, expected %d\n",
145             n, noutput_items);
146     return -1;
147   }
148
149   for (int i = 0; i < noutput_items; i++){
150     if (jd[i]->status != JS_OK){
151       fprintf(stderr, "gcell_fft_vcc jd[%d]->status = %s\n",
152               i, gc_job_status_string(jd[i]->status).c_str());
153       return -1;
154     }
155   }
156
157   return noutput_items;
158 }
159