kissfft.hh
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2003-2010, Mark Borgerding. All rights reserved.
3  * This file is part of KISS FFT - https://github.com/mborgerding/kissfft
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  * See COPYING file for more information.
7  */
8 
9 #ifndef KISSFFT_CLASS_HH
10 #define KISSFFT_CLASS_HH
11 #include <complex>
12 #include <utility>
13 #include <vector>
14 
15 
16 template <typename scalar_t>
17 class kissfft
18 {
19  public:
20 
21  typedef std::complex<scalar_t> cpx_t;
22 
23  kissfft( const std::size_t nfft,
24  const bool inverse )
25  :_nfft(nfft)
26  ,_inverse(inverse)
27  {
28  // fill twiddle factors
29  _twiddles.resize(_nfft);
30  const scalar_t phinc = (_inverse?2:-2)* std::acos( (scalar_t) -1) / _nfft;
31  for (std::size_t i=0;i<_nfft;++i)
32  _twiddles[i] = std::exp( cpx_t(0,i*phinc) );
33 
34  //factorize
35  //start factoring out 4's, then 2's, then 3,5,7,9,...
36  std::size_t n= _nfft;
37  std::size_t p=4;
38  do {
39  while (n % p) {
40  switch (p) {
41  case 4: p = 2; break;
42  case 2: p = 3; break;
43  default: p += 2; break;
44  }
45  if (p*p>n)
46  p = n;// no more factors
47  }
48  n /= p;
49  _stageRadix.push_back(p);
50  _stageRemainder.push_back(n);
51  }while(n>1);
52  }
53 
54 
61  void assign( const std::size_t nfft,
62  const bool inverse )
63  {
64  if ( nfft != _nfft )
65  {
66  kissfft tmp( nfft, inverse ); // O(n) time.
67  std::swap( tmp, *this ); // this is O(1) in C++11, O(n) otherwise.
68  }
69  else if ( inverse != _inverse )
70  {
71  // conjugate the twiddle factors.
72  for ( typename std::vector<cpx_t>::iterator it = _twiddles.begin();
73  it != _twiddles.end(); ++it )
74  it->imag( -it->imag() );
75  }
76  }
77 
90  void transform(const cpx_t * fft_in, cpx_t * fft_out, const std::size_t stage = 0, const std::size_t fstride = 1, const std::size_t in_stride = 1) const
91  {
92  const std::size_t p = _stageRadix[stage];
93  const std::size_t m = _stageRemainder[stage];
94  cpx_t * const Fout_beg = fft_out;
95  cpx_t * const Fout_end = fft_out + p*m;
96 
97  if (m==1) {
98  do{
99  *fft_out = *fft_in;
100  fft_in += fstride*in_stride;
101  }while(++fft_out != Fout_end );
102  }else{
103  do{
104  // recursive call:
105  // DFT of size m*p performed by doing
106  // p instances of smaller DFTs of size m,
107  // each one takes a decimated version of the input
108  transform(fft_in, fft_out, stage+1, fstride*p,in_stride);
109  fft_in += fstride*in_stride;
110  }while( (fft_out += m) != Fout_end );
111  }
112 
113  fft_out=Fout_beg;
114 
115  // recombine the p smaller DFTs
116  switch (p) {
117  case 2: kf_bfly2(fft_out,fstride,m); break;
118  case 3: kf_bfly3(fft_out,fstride,m); break;
119  case 4: kf_bfly4(fft_out,fstride,m); break;
120  case 5: kf_bfly5(fft_out,fstride,m); break;
121  default: kf_bfly_generic(fft_out,fstride,m,p); break;
122  }
123  }
124 
154  void transform_real( const scalar_t * const src,
155  cpx_t * const dst ) const
156  {
157  const std::size_t N = _nfft;
158  if ( N == 0 )
159  return;
160 
161  // perform complex FFT
162  transform( reinterpret_cast<const cpx_t*>(src), dst );
163 
164  // post processing for k = 0 and k = N
165  dst[0] = cpx_t( dst[0].real() + dst[0].imag(),
166  dst[0].real() - dst[0].imag() );
167 
168  // post processing for all the other k = 1, 2, ..., N-1
169  const scalar_t pi = std::acos( (scalar_t) -1);
170  const scalar_t half_phi_inc = ( _inverse ? pi : -pi ) / N;
171  const cpx_t twiddle_mul = std::exp( cpx_t(0, half_phi_inc) );
172  for ( std::size_t k = 1; 2*k < N; ++k )
173  {
174  const cpx_t w = (scalar_t)0.5 * cpx_t(
175  dst[k].real() + dst[N-k].real(),
176  dst[k].imag() - dst[N-k].imag() );
177  const cpx_t z = (scalar_t)0.5 * cpx_t(
178  dst[k].imag() + dst[N-k].imag(),
179  -dst[k].real() + dst[N-k].real() );
180  const cpx_t twiddle =
181  k % 2 == 0 ?
182  _twiddles[k/2] :
183  _twiddles[k/2] * twiddle_mul;
184  dst[ k] = w + twiddle * z;
185  dst[N-k] = std::conj( w - twiddle * z );
186  }
187  if ( N % 2 == 0 )
188  dst[N/2] = std::conj( dst[N/2] );
189  }
190 
191  private:
192 
193  void kf_bfly2( cpx_t * Fout, const size_t fstride, const std::size_t m) const
194  {
195  for (std::size_t k=0;k<m;++k) {
196  const cpx_t t = Fout[m+k] * _twiddles[k*fstride];
197  Fout[m+k] = Fout[k] - t;
198  Fout[k] += t;
199  }
200  }
201 
202  void kf_bfly3( cpx_t * Fout, const std::size_t fstride, const std::size_t m) const
203  {
204  std::size_t k=m;
205  const std::size_t m2 = 2*m;
206  const cpx_t *tw1,*tw2;
207  cpx_t scratch[5];
208  const cpx_t epi3 = _twiddles[fstride*m];
209 
210  tw1=tw2=&_twiddles[0];
211 
212  do{
213  scratch[1] = Fout[m] * *tw1;
214  scratch[2] = Fout[m2] * *tw2;
215 
216  scratch[3] = scratch[1] + scratch[2];
217  scratch[0] = scratch[1] - scratch[2];
218  tw1 += fstride;
219  tw2 += fstride*2;
220 
221  Fout[m] = Fout[0] - scratch[3]*scalar_t(0.5);
222  scratch[0] *= epi3.imag();
223 
224  Fout[0] += scratch[3];
225 
226  Fout[m2] = cpx_t( Fout[m].real() + scratch[0].imag() , Fout[m].imag() - scratch[0].real() );
227 
228  Fout[m] += cpx_t( -scratch[0].imag(),scratch[0].real() );
229  ++Fout;
230  }while(--k);
231  }
232 
233  void kf_bfly4( cpx_t * const Fout, const std::size_t fstride, const std::size_t m) const
234  {
235  cpx_t scratch[7];
236  const scalar_t negative_if_inverse = _inverse ? -1 : +1;
237  for (std::size_t k=0;k<m;++k) {
238  scratch[0] = Fout[k+ m] * _twiddles[k*fstride ];
239  scratch[1] = Fout[k+2*m] * _twiddles[k*fstride*2];
240  scratch[2] = Fout[k+3*m] * _twiddles[k*fstride*3];
241  scratch[5] = Fout[k] - scratch[1];
242 
243  Fout[k] += scratch[1];
244  scratch[3] = scratch[0] + scratch[2];
245  scratch[4] = scratch[0] - scratch[2];
246  scratch[4] = cpx_t( scratch[4].imag()*negative_if_inverse ,
247  -scratch[4].real()*negative_if_inverse );
248 
249  Fout[k+2*m] = Fout[k] - scratch[3];
250  Fout[k ]+= scratch[3];
251  Fout[k+ m] = scratch[5] + scratch[4];
252  Fout[k+3*m] = scratch[5] - scratch[4];
253  }
254  }
255 
256  void kf_bfly5( cpx_t * const Fout, const std::size_t fstride, const std::size_t m) const
257  {
258  cpx_t *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
259  cpx_t scratch[13];
260  const cpx_t ya = _twiddles[fstride*m];
261  const cpx_t yb = _twiddles[fstride*2*m];
262 
263  Fout0=Fout;
264  Fout1=Fout0+m;
265  Fout2=Fout0+2*m;
266  Fout3=Fout0+3*m;
267  Fout4=Fout0+4*m;
268 
269  for ( std::size_t u=0; u<m; ++u ) {
270  scratch[0] = *Fout0;
271 
272  scratch[1] = *Fout1 * _twiddles[ u*fstride];
273  scratch[2] = *Fout2 * _twiddles[2*u*fstride];
274  scratch[3] = *Fout3 * _twiddles[3*u*fstride];
275  scratch[4] = *Fout4 * _twiddles[4*u*fstride];
276 
277  scratch[7] = scratch[1] + scratch[4];
278  scratch[10]= scratch[1] - scratch[4];
279  scratch[8] = scratch[2] + scratch[3];
280  scratch[9] = scratch[2] - scratch[3];
281 
282  *Fout0 += scratch[7];
283  *Fout0 += scratch[8];
284 
285  scratch[5] = scratch[0] + cpx_t(
286  scratch[7].real()*ya.real() + scratch[8].real()*yb.real(),
287  scratch[7].imag()*ya.real() + scratch[8].imag()*yb.real()
288  );
289 
290  scratch[6] = cpx_t(
291  scratch[10].imag()*ya.imag() + scratch[9].imag()*yb.imag(),
292  -scratch[10].real()*ya.imag() - scratch[9].real()*yb.imag()
293  );
294 
295  *Fout1 = scratch[5] - scratch[6];
296  *Fout4 = scratch[5] + scratch[6];
297 
298  scratch[11] = scratch[0] +
299  cpx_t(
300  scratch[7].real()*yb.real() + scratch[8].real()*ya.real(),
301  scratch[7].imag()*yb.real() + scratch[8].imag()*ya.real()
302  );
303 
304  scratch[12] = cpx_t(
305  -scratch[10].imag()*yb.imag() + scratch[9].imag()*ya.imag(),
306  scratch[10].real()*yb.imag() - scratch[9].real()*ya.imag()
307  );
308 
309  *Fout2 = scratch[11] + scratch[12];
310  *Fout3 = scratch[11] - scratch[12];
311 
312  ++Fout0;
313  ++Fout1;
314  ++Fout2;
315  ++Fout3;
316  ++Fout4;
317  }
318  }
319 
320  /* perform the butterfly for one stage of a mixed radix FFT */
322  cpx_t * const Fout,
323  const size_t fstride,
324  const std::size_t m,
325  const std::size_t p
326  ) const
327  {
328  const cpx_t * twiddles = &_twiddles[0];
329 
330  if(p > _scratchbuf.size()) _scratchbuf.resize(p);
331 
332  for ( std::size_t u=0; u<m; ++u ) {
333  std::size_t k = u;
334  for ( std::size_t q1=0 ; q1<p ; ++q1 ) {
335  _scratchbuf[q1] = Fout[ k ];
336  k += m;
337  }
338 
339  k=u;
340  for ( std::size_t q1=0 ; q1<p ; ++q1 ) {
341  std::size_t twidx=0;
342  Fout[ k ] = _scratchbuf[0];
343  for ( std::size_t q=1;q<p;++q ) {
344  twidx += fstride * k;
345  if (twidx>=_nfft)
346  twidx-=_nfft;
347  Fout[ k ] += _scratchbuf[q] * twiddles[twidx];
348  }
349  k += m;
350  }
351  }
352  }
353 
355  bool _inverse;
356  std::vector<cpx_t> _twiddles;
357  std::vector<std::size_t> _stageRadix;
358  std::vector<std::size_t> _stageRemainder;
359  mutable std::vector<cpx_t> _scratchbuf;
360 };
361 #endif
nonstd::span_lite::size_t
span_CONFIG_SIZE_TYPE size_t
Definition: span.hpp:576
kissfft::_inverse
bool _inverse
Definition: kissfft.hh:355
kissfft::kf_bfly5
void kf_bfly5(cpx_t *const Fout, const std::size_t fstride, const std::size_t m) const
Definition: kissfft.hh:256
kissfft::_stageRadix
std::vector< std::size_t > _stageRadix
Definition: kissfft.hh:357
kissfft
Definition: kissfft.hh:17
kissfft::kissfft
kissfft(const std::size_t nfft, const bool inverse)
Definition: kissfft.hh:23
mqtt_test_proto.z
z
Definition: mqtt_test_proto.py:36
kissfft::cpx_t
std::complex< scalar_t > cpx_t
Definition: kissfft.hh:21
kissfft::kf_bfly4
void kf_bfly4(cpx_t *const Fout, const std::size_t fstride, const std::size_t m) const
Definition: kissfft.hh:233
kissfft::_stageRemainder
std::vector< std::size_t > _stageRemainder
Definition: kissfft.hh:358
std::swap
NLOHMANN_BASIC_JSON_TPL_DECLARATION void swap(nlohmann::NLOHMANN_BASIC_JSON_TPL &j1, nlohmann::NLOHMANN_BASIC_JSON_TPL &j2) noexcept(//NOLINT(readability-inconsistent-declaration-parameter-name) is_nothrow_move_constructible< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value &&//NOLINT(misc-redundant-expression) is_nothrow_move_assignable< nlohmann::NLOHMANN_BASIC_JSON_TPL >::value)
exchanges the values of two JSON objects
Definition: json.hpp:21884
kissfft::kf_bfly3
void kf_bfly3(cpx_t *Fout, const std::size_t fstride, const std::size_t m) const
Definition: kissfft.hh:202
kissfft::kf_bfly_generic
void kf_bfly_generic(cpx_t *const Fout, const size_t fstride, const std::size_t m, const std::size_t p) const
Definition: kissfft.hh:321
kissfft::assign
void assign(const std::size_t nfft, const bool inverse)
Definition: kissfft.hh:61
kissfft::transform_real
void transform_real(const scalar_t *const src, cpx_t *const dst) const
Definition: kissfft.hh:154
kissfft::transform
void transform(const cpx_t *fft_in, cpx_t *fft_out, const std::size_t stage=0, const std::size_t fstride=1, const std::size_t in_stride=1) const
Definition: kissfft.hh:90
kissfft::_scratchbuf
std::vector< cpx_t > _scratchbuf
Definition: kissfft.hh:359
kissfft::_nfft
std::size_t _nfft
Definition: kissfft.hh:354
kissfft::_twiddles
std::vector< cpx_t > _twiddles
Definition: kissfft.hh:356
kissfft::kf_bfly2
void kf_bfly2(cpx_t *Fout, const size_t fstride, const std::size_t m) const
Definition: kissfft.hh:193
dst
char * dst
Definition: lz4.h:792


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Aug 11 2024 02:24:23