1 module dplug.dsp.rfft; 2 3 /** 4 5 FFTReal.hpp 6 By Laurent de Soras 7 8 --- Legal stuff --- 9 10 This program is free software. It comes without any warranty, to 11 the extent permitted by applicable law. You can redistribute it 12 and/or modify it under the terms of the Do What The Fuck You Want 13 To Public License, Version 2, as published by Sam Hocevar. See 14 http://sam.zoy.org/wtfpl/COPYING for more details. 15 16 */ 17 /** 18 * Copyright: Copyright Auburn Sounds 2016. 19 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 20 * Authors: Guillaume Piolat 21 * What has changed? Shuffling was added to have a similar output than the regular complex FFT. 22 */ 23 import std.math: PI, sin, cos, SQRT1_2; 24 import std.complex; 25 26 import dplug.core.math; 27 import dplug.core.alignedbuffer; 28 29 30 /// Performs FFT from real input, and IFFT towards real output. 31 struct RFFT(T) 32 { 33 public: 34 nothrow: 35 @nogc: 36 37 // Over this bit depth, we use direct calculation for sin/cos 38 enum TRIGO_BD_LIMIT = 12; 39 40 void initialize(int length) 41 { 42 assert(length > 0); 43 assert(isPowerOfTwo(length)); 44 _length = length; 45 _nbr_bits = iFloorLog2(length); 46 init_br_lut(); 47 init_trigo_lut(); 48 init_trigo_osc(); 49 _buffer.reallocBuffer(_length); 50 _shuffledValues.reallocBuffer(_length); 51 } 52 53 ~this() 54 { 55 _br_lut.reallocBuffer(0); 56 _trigo_lut.reallocBuffer(0); 57 _trigo_osc.reallocBuffer(0); 58 _buffer.reallocBuffer(0); // temporary buffer 59 _shuffledValues.reallocBuffer(0); 60 } 61 62 /** 63 * Compute the Real FFT of the array. 64 * Params: 65 * timeData Input array (N time samples) 66 * outputBins Destination coefficients (N/2 + 1 frequency bins) 67 */ 68 void forwardTransform(const(T)[] timeData, Complex!T[] outputBins) 69 { 70 assert(timeData.length == _length); 71 assert(outputBins.length == (_length/2)+1); 72 73 T[] f = _shuffledValues; 74 75 if (_nbr_bits > 2) 76 { 77 compute_fft_general(f.ptr, timeData.ptr); 78 } 79 else if (_nbr_bits == 2) // 4-point FFT 80 { 81 f[1] = timeData[0] - timeData[2]; 82 f[3] = timeData[1] - timeData[3]; 83 84 T b_0 = timeData[0] + timeData[2]; 85 T b_2 = timeData[1] + timeData[3]; 86 87 f[0] = b_0 + b_2; 88 f[2] = b_0 - b_2; 89 } 90 else if (_nbr_bits == 1) // 2-point FFT 91 { 92 f [0] = timeData[0] + timeData[1]; 93 f [1] = timeData[0] - timeData[1]; 94 } 95 else 96 { 97 f[0] = timeData[0]; // 1-point FFT 98 } 99 100 // At this point, f contains: 101 // f destination array (frequency bins) 102 // f[0...length(x)/2] = real values, 103 // f[length(x)/2+1...length(x)-1] = negative imaginary values of coefficents 1...length(x)/2-1. 104 // So we have to reshuffle them to have nice complex bins. 105 int mid = _length/2; 106 outputBins[0] = Complex!T(f[0], 0); 107 for(int i = 1; i < mid; ++i) 108 outputBins[i] = Complex!T(f[i], -f[mid+i]); 109 outputBins[mid] = Complex!T(f[mid], 0); // for length 1, this still works 110 } 111 112 /** 113 * Compute the inverse FFT of the array. Perform post-scaling. 114 * 115 * Params: 116 * inputBins Source arrays (N/2 + 1 frequency bins) 117 * timeData Destination array (N time samples). 118 * 119 * Note: 120 * This transform has the benefit you don't have to conjugate the "mirorred" part of the FFT. 121 * Excess data in imaginary part of DC and Nyquist bins are ignored. 122 */ 123 void reverseTransform(Complex!T[] inputBins, T[] timeData) 124 { 125 int mid = _length/2; 126 assert(inputBins.length == mid+1); // expect _length/2+1 complex numbers, 127 assert(timeData.length == _length); 128 129 // On inverse transform, scale down result 130 T invMultiplier = cast(T)1 / _length; 131 132 // Shuffle input frequency bins, and scale down. 133 T[] f = _shuffledValues; 134 for(int i = 0; i <= mid; ++i) 135 f[i] = inputBins[i].re * invMultiplier; 136 for(int i = mid+1; i < _length; ++i) 137 f[i] = -inputBins[i-mid].im * invMultiplier; 138 139 // At this point, the format in f is: 140 // f [0...length(x)/2] = real values 141 // f [length(x)/2+1...length(x)-1] = negative imaginary values of coefficents 1...length(x)/2-1. 142 // Which is suitable for the RealFFT algorithm. 143 144 if (_nbr_bits > 2) // General case 145 { 146 compute_ifft_general(f.ptr, timeData.ptr); 147 } 148 else if (_nbr_bits == 2) // 4-point IFFT 149 { 150 const(T) b_0 = f[0] + f[2]; 151 const(T) b_2 = f[0] - f[2]; 152 timeData[0] = b_0 + f[1] * 2; 153 timeData[2] = b_0 - f[1] * 2; 154 timeData[1] = b_2 + f[3] * 2; 155 timeData[3] = b_2 - f[3] * 2; 156 } 157 else if (_nbr_bits == 1) // 2-point IFFT 158 { 159 timeData[0] = f[0] + f[1]; 160 timeData[1] = f[0] - f[1]; 161 } 162 else // 1-point IFFT 163 { 164 timeData[0] = f[0]; 165 } 166 } 167 168 private: 169 170 int _nbr_bits; 171 int _length; 172 int[] _br_lut; 173 T[] _trigo_lut; 174 OscSinCos!T[] _trigo_osc; 175 T[] _buffer; // temporary buffer 176 T[] _shuffledValues; // shuffled values, output of the RFFT and input of IRFFT 177 178 // Returns: temporary buffer 179 T* use_buffer() 180 { 181 return _buffer.ptr; 182 } 183 184 const(int)* get_br_ptr() pure const 185 { 186 return _br_lut.ptr; 187 } 188 189 int get_trigo_level_index(int level) pure const 190 { 191 assert(level >= 3); 192 return((1 << (level - 1)) - 4); 193 } 194 195 const(T)* get_trigo_ptr(int level) pure const 196 { 197 return (&_trigo_lut [get_trigo_level_index (level)]); 198 } 199 200 void init_br_lut () 201 { 202 int length = 1 << _nbr_bits; 203 _br_lut.reallocBuffer(length); 204 _br_lut[0] = 0; 205 int br_index = 0; 206 for (int cnt = 1; cnt < length; ++cnt) 207 { 208 // ++br_index (bit reversed) 209 int bit = length >> 1; 210 while (((br_index ^= bit) & bit) == 0) 211 { 212 bit >>= 1; 213 } 214 _br_lut[cnt] = br_index; 215 } 216 } 217 218 void init_trigo_lut() 219 { 220 if (_nbr_bits > 3) 221 { 222 int total_len = (1 << (_nbr_bits - 1)) - 4; 223 _trigo_lut.reallocBuffer(total_len); 224 225 for (int level = 3; level < _nbr_bits; ++level) 226 { 227 int level_len = 1 << (level - 1); 228 T* level_ptr = &_trigo_lut [get_trigo_level_index (level)]; 229 double mul = PI / (level_len << 1); 230 for (int i = 0; i < level_len; ++ i) 231 { 232 level_ptr[i] = cast(T)(cos (i * mul)); 233 } 234 } 235 } 236 } 237 238 void init_trigo_osc () 239 { 240 int nbr_osc = _nbr_bits - TRIGO_BD_LIMIT; 241 if (nbr_osc > 0) 242 { 243 _trigo_osc.reallocBuffer(nbr_osc); 244 for (int osc_cnt = 0; osc_cnt < nbr_osc; ++osc_cnt) 245 { 246 const int len = 1 << (TRIGO_BD_LIMIT + osc_cnt); 247 const double mul = (0.5 * PI) / len; 248 _trigo_osc[osc_cnt].setStep(mul); 249 } 250 } 251 } 252 253 // Transform in several passes 254 void compute_fft_general (T* f, const(T)* x) 255 { 256 T* sf; 257 T* df; 258 259 if ((_nbr_bits & 1) != 0) 260 { 261 df = use_buffer(); 262 sf = f; 263 } 264 else 265 { 266 df = f; 267 sf = use_buffer(); 268 } 269 270 compute_direct_pass_1_2 (df, x); 271 compute_direct_pass_3 (sf, df); 272 273 for (int pass = 3; pass < _nbr_bits; ++ pass) 274 { 275 compute_direct_pass_n (df, sf, pass); 276 T* temp_ptr = df; 277 df = sf; 278 sf = temp_ptr; 279 } 280 } 281 282 void compute_direct_pass_1_2 (T* df, const(T)* x) 283 { 284 const(int)* bit_rev_lut_ptr = get_br_ptr(); 285 int coef_index = 0; 286 do 287 { 288 const int rev_index_0 = bit_rev_lut_ptr [coef_index]; 289 const int rev_index_1 = bit_rev_lut_ptr [coef_index + 1]; 290 const int rev_index_2 = bit_rev_lut_ptr [coef_index + 2]; 291 const int rev_index_3 = bit_rev_lut_ptr [coef_index + 3]; 292 293 T* df2 = df + coef_index; 294 df2 [1] = x [rev_index_0] - x [rev_index_1]; 295 df2 [3] = x [rev_index_2] - x [rev_index_3]; 296 297 const(T) sf_0 = x [rev_index_0] + x [rev_index_1]; 298 const(T) sf_2 = x [rev_index_2] + x [rev_index_3]; 299 300 df2 [0] = sf_0 + sf_2; 301 df2 [2] = sf_0 - sf_2; 302 303 coef_index += 4; 304 } 305 while (coef_index < _length); 306 } 307 308 309 310 void compute_direct_pass_3 (T* df, const(T)* sf) 311 { 312 alias sqrt2_2 = SQRT1_2; 313 int coef_index = 0; 314 do 315 { 316 T v; 317 318 df [coef_index] = sf [coef_index] + sf [coef_index + 4]; 319 df [coef_index + 4] = sf [coef_index] - sf [coef_index + 4]; 320 df [coef_index + 2] = sf [coef_index + 2]; 321 df [coef_index + 6] = sf [coef_index + 6]; 322 323 v = (sf [coef_index + 5] - sf [coef_index + 7]) * sqrt2_2; 324 df [coef_index + 1] = sf [coef_index + 1] + v; 325 df [coef_index + 3] = sf [coef_index + 1] - v; 326 327 v = (sf [coef_index + 5] + sf [coef_index + 7]) * sqrt2_2; 328 df [coef_index + 5] = v + sf [coef_index + 3]; 329 df [coef_index + 7] = v - sf [coef_index + 3]; 330 331 coef_index += 8; 332 } 333 while (coef_index < _length); 334 } 335 336 void compute_direct_pass_n (T* df, const(T)* sf, int pass) 337 { 338 assert (pass >= 3); 339 assert (pass < _nbr_bits); 340 341 if (pass <= TRIGO_BD_LIMIT) 342 { 343 compute_direct_pass_n_lut (df, sf, pass); 344 } 345 else 346 { 347 compute_direct_pass_n_osc (df, sf, pass); 348 } 349 } 350 351 352 353 void compute_direct_pass_n_lut (T* df, const(T)* sf, int pass) 354 { 355 assert (pass >= 3); 356 assert (pass < _nbr_bits); 357 358 const int nbr_coef = 1 << pass; 359 const int h_nbr_coef = nbr_coef >> 1; 360 const int d_nbr_coef = nbr_coef << 1; 361 int coef_index = 0; 362 const(T) * cos_ptr = get_trigo_ptr (pass); 363 do 364 { 365 const(T) * sf1r = sf + coef_index; 366 const(T) * sf2r = sf1r + nbr_coef; 367 T * dfr = df + coef_index; 368 T * dfi = dfr + nbr_coef; 369 370 // Extreme coefficients are always real 371 dfr [0] = sf1r [0] + sf2r [0]; 372 dfi [0] = sf1r [0] - sf2r [0]; // dfr [nbr_coef] = 373 dfr [h_nbr_coef] = sf1r [h_nbr_coef]; 374 dfi [h_nbr_coef] = sf2r [h_nbr_coef]; 375 376 // Others are conjugate complex numbers 377 const(T) * sf1i = sf1r + h_nbr_coef; 378 const(T) * sf2i = sf1i + nbr_coef; 379 for (int i = 1; i < h_nbr_coef; ++ i) 380 { 381 const(T) c = cos_ptr [i]; // cos (i*PI/nbr_coef); 382 const(T) s = cos_ptr [h_nbr_coef - i]; // sin (i*PI/nbr_coef); 383 T v; 384 385 v = sf2r [i] * c - sf2i [i] * s; 386 dfr [i] = sf1r [i] + v; 387 dfi [-i] = sf1r [i] - v; // dfr [nbr_coef - i] = 388 389 v = sf2r [i] * s + sf2i [i] * c; 390 dfi [i] = v + sf1i [i]; 391 dfi [nbr_coef - i] = v - sf1i [i]; 392 } 393 394 coef_index += d_nbr_coef; 395 } 396 while (coef_index < _length); 397 } 398 399 void compute_direct_pass_n_osc (T* df, const(T)* sf, int pass) 400 { 401 assert (pass > TRIGO_BD_LIMIT); 402 assert (pass < _nbr_bits); 403 404 const int nbr_coef = 1 << pass; 405 const int h_nbr_coef = nbr_coef >> 1; 406 const int d_nbr_coef = nbr_coef << 1; 407 int coef_index = 0; 408 OscSinCos!T* osc = &_trigo_osc[pass - (TRIGO_BD_LIMIT + 1)]; 409 do 410 { 411 const(T) * sf1r = sf + coef_index; 412 const(T) * sf2r = sf1r + nbr_coef; 413 T * dfr = df + coef_index; 414 T * dfi = dfr + nbr_coef; 415 416 osc.resetPhase(); 417 418 // Extreme coefficients are always real 419 dfr [0] = sf1r [0] + sf2r [0]; 420 dfi [0] = sf1r [0] - sf2r [0]; // dfr [nbr_coef] = 421 dfr [h_nbr_coef] = sf1r [h_nbr_coef]; 422 dfi [h_nbr_coef] = sf2r [h_nbr_coef]; 423 424 // Others are conjugate complex numbers 425 const(T) * sf1i = sf1r + h_nbr_coef; 426 const(T) * sf2i = sf1i + nbr_coef; 427 for (int i = 1; i < h_nbr_coef; ++ i) 428 { 429 osc.step (); 430 const(T) c = osc.getCos; 431 const(T) s = osc.getSin; 432 T v; 433 434 v = sf2r [i] * c - sf2i [i] * s; 435 dfr [i] = sf1r [i] + v; 436 dfi [-i] = sf1r [i] - v; // dfr [nbr_coef - i] = 437 438 v = sf2r [i] * s + sf2i [i] * c; 439 dfi [i] = v + sf1i [i]; 440 dfi [nbr_coef - i] = v - sf1i [i]; 441 } 442 443 coef_index += d_nbr_coef; 444 } 445 while (coef_index < _length); 446 } 447 448 // Transform in several pass 449 void compute_ifft_general (const(T)* f, T* x) 450 { 451 T* sf = cast(T*)(f); 452 T * df; 453 T * df_temp; 454 455 if (_nbr_bits & 1) 456 { 457 df = use_buffer(); 458 df_temp = x; 459 } 460 else 461 { 462 df = x; 463 df_temp = use_buffer(); 464 } 465 466 for (int pass = _nbr_bits - 1; pass >= 3; -- pass) 467 { 468 compute_inverse_pass_n (df, sf, pass); 469 470 if (pass < _nbr_bits - 1) 471 { 472 T* temp_ptr = df; 473 df = sf; 474 sf = temp_ptr; 475 } 476 else 477 { 478 sf = df; 479 df = df_temp; 480 } 481 } 482 483 compute_inverse_pass_3 (df, sf); 484 compute_inverse_pass_1_2 (x, df); 485 } 486 487 void compute_inverse_pass_n (T* df, const(T)* sf, int pass) 488 { 489 assert (pass >= 3); 490 assert (pass < _nbr_bits); 491 492 if (pass <= TRIGO_BD_LIMIT) 493 { 494 compute_inverse_pass_n_lut (df, sf, pass); 495 } 496 else 497 { 498 compute_inverse_pass_n_osc (df, sf, pass); 499 } 500 } 501 502 void compute_inverse_pass_n_lut (T* df, const(T)* sf, int pass) 503 { 504 assert (pass >= 3); 505 assert (pass < _nbr_bits); 506 507 const int nbr_coef = 1 << pass; 508 const int h_nbr_coef = nbr_coef >> 1; 509 const int d_nbr_coef = nbr_coef << 1; 510 int coef_index = 0; 511 const(T)* cos_ptr = get_trigo_ptr (pass); 512 do 513 { 514 const(T) * sfr = sf + coef_index; 515 const(T) * sfi = sfr + nbr_coef; 516 T * df1r = df + coef_index; 517 T * df2r = df1r + nbr_coef; 518 519 // Extreme coefficients are always real 520 df1r [0] = sfr [0] + sfi [0]; // + sfr [nbr_coef] 521 df2r [0] = sfr [0] - sfi [0]; // - sfr [nbr_coef] 522 df1r [h_nbr_coef] = sfr [h_nbr_coef] * 2; 523 df2r [h_nbr_coef] = sfi [h_nbr_coef] * 2; 524 525 // Others are conjugate complex numbers 526 T * df1i = df1r + h_nbr_coef; 527 T * df2i = df1i + nbr_coef; 528 for (int i = 1; i < h_nbr_coef; ++ i) 529 { 530 df1r [i] = sfr [i] + sfi [-i]; // + sfr [nbr_coef - i] 531 df1i [i] = sfi [i] - sfi [nbr_coef - i]; 532 533 const(T) c = cos_ptr [i]; // cos (i*PI/nbr_coef); 534 const(T) s = cos_ptr [h_nbr_coef - i]; // sin (i*PI/nbr_coef); 535 const(T) vr = sfr [i] - sfi [-i]; // - sfr [nbr_coef - i] 536 const(T) vi = sfi [i] + sfi [nbr_coef - i]; 537 538 df2r [i] = vr * c + vi * s; 539 df2i [i] = vi * c - vr * s; 540 } 541 542 coef_index += d_nbr_coef; 543 } 544 while (coef_index < _length); 545 } 546 547 void compute_inverse_pass_n_osc (T* df, const(T)* sf, int pass) 548 { 549 assert (pass > TRIGO_BD_LIMIT); 550 assert (pass < _nbr_bits); 551 552 const int nbr_coef = 1 << pass; 553 const int h_nbr_coef = nbr_coef >> 1; 554 const int d_nbr_coef = nbr_coef << 1; 555 int coef_index = 0; 556 OscSinCos!T* osc = &_trigo_osc[pass - (TRIGO_BD_LIMIT + 1)]; 557 do 558 { 559 const(T) * sfr = sf + coef_index; 560 const(T) * sfi = sfr + nbr_coef; 561 T * df1r = df + coef_index; 562 T * df2r = df1r + nbr_coef; 563 564 osc.resetPhase (); 565 566 // Extreme coefficients are always real 567 df1r [0] = sfr [0] + sfi [0]; // + sfr [nbr_coef] 568 df2r [0] = sfr [0] - sfi [0]; // - sfr [nbr_coef] 569 df1r [h_nbr_coef] = sfr [h_nbr_coef] * 2; 570 df2r [h_nbr_coef] = sfi [h_nbr_coef] * 2; 571 572 // Others are conjugate complex numbers 573 T * df1i = df1r + h_nbr_coef; 574 T * df2i = df1i + nbr_coef; 575 for (int i = 1; i < h_nbr_coef; ++ i) 576 { 577 df1r [i] = sfr [i] + sfi [-i]; // + sfr [nbr_coef - i] 578 df1i [i] = sfi [i] - sfi [nbr_coef - i]; 579 580 osc.step (); 581 const(T) c = osc.getCos; 582 const(T) s = osc.getSin; 583 const(T) vr = sfr [i] - sfi [-i]; // - sfr [nbr_coef - i] 584 const(T) vi = sfi [i] + sfi [nbr_coef - i]; 585 586 df2r [i] = vr * c + vi * s; 587 df2i [i] = vi * c - vr * s; 588 } 589 590 coef_index += d_nbr_coef; 591 } 592 while (coef_index < _length); 593 } 594 595 596 597 void compute_inverse_pass_3 (T* df, const(T)* sf) 598 { 599 alias sqrt2_2 = SQRT1_2; 600 int coef_index = 0; 601 do 602 { 603 df [coef_index] = sf [coef_index] + sf [coef_index + 4]; 604 df [coef_index + 4] = sf [coef_index] - sf [coef_index + 4]; 605 df [coef_index + 2] = sf [coef_index + 2] * 2; 606 df [coef_index + 6] = sf [coef_index + 6] * 2; 607 608 df [coef_index + 1] = sf [coef_index + 1] + sf [coef_index + 3]; 609 df [coef_index + 3] = sf [coef_index + 5] - sf [coef_index + 7]; 610 611 const(T) vr = sf [coef_index + 1] - sf [coef_index + 3]; 612 const(T) vi = sf [coef_index + 5] + sf [coef_index + 7]; 613 614 df [coef_index + 5] = (vr + vi) * sqrt2_2; 615 df [coef_index + 7] = (vi - vr) * sqrt2_2; 616 617 coef_index += 8; 618 } 619 while (coef_index < _length); 620 } 621 622 void compute_inverse_pass_1_2 (T* x, const(T)* sf) 623 { 624 const(int) * bit_rev_lut_ptr = get_br_ptr (); 625 const(T) * sf2 = sf; 626 int coef_index = 0; 627 do 628 { 629 { 630 const(T) b_0 = sf2 [0] + sf2 [2]; 631 const(T) b_2 = sf2 [0] - sf2 [2]; 632 const(T) b_1 = sf2 [1] * 2; 633 const(T) b_3 = sf2 [3] * 2; 634 635 x [bit_rev_lut_ptr [0]] = b_0 + b_1; 636 x [bit_rev_lut_ptr [1]] = b_0 - b_1; 637 x [bit_rev_lut_ptr [2]] = b_2 + b_3; 638 x [bit_rev_lut_ptr [3]] = b_2 - b_3; 639 } 640 { 641 const(T) b_0 = sf2 [4] + sf2 [6]; 642 const(T) b_2 = sf2 [4] - sf2 [6]; 643 const(T) b_1 = sf2 [5] * 2; 644 const(T) b_3 = sf2 [7] * 2; 645 646 x [bit_rev_lut_ptr [4]] = b_0 + b_1; 647 x [bit_rev_lut_ptr [5]] = b_0 - b_1; 648 x [bit_rev_lut_ptr [6]] = b_2 + b_3; 649 x [bit_rev_lut_ptr [7]] = b_2 - b_3; 650 } 651 652 sf2 += 8; 653 coef_index += 8; 654 bit_rev_lut_ptr += 8; 655 } 656 while (coef_index < _length); 657 } 658 659 static struct OscSinCos(T) 660 { 661 public: 662 nothrow: 663 pure: 664 @nogc: 665 void setStep(double angleRad) 666 { 667 _step_cos = cast(T)(cos(angleRad)); 668 _step_sin = cast(T)(sin(angleRad)); 669 } 670 671 alias getCos = _pos_cos; 672 alias getSin = _pos_sin; 673 674 void resetPhase() 675 { 676 _pos_cos = 1; 677 _pos_sin = 0; 678 } 679 680 void step() 681 { 682 T old_cos = _pos_cos; 683 T old_sin = _pos_sin; 684 _pos_cos = old_cos * _step_cos - old_sin * _step_sin; 685 _pos_sin = old_cos * _step_sin + old_sin * _step_cos; 686 } 687 688 T _pos_cos = 1; // Current phase expressed with sin and cos. [-1 ; 1] 689 T _pos_sin = 0; // - 690 T _step_cos = 1; // Phase increment per step, [-1 ; 1] 691 T _step_sin = 0; // - 692 } 693 } 694 695 unittest 696 { 697 import std.numeric: fft, approxEqual; 698 import dplug.dsp.rfft; 699 import std.stdio; // TEMP 700 import dplug.core.random; 701 702 auto random = defaultGlobalRNG(); 703 704 void testRFFT(T)(T[] A) 705 { 706 // Takes reference fft 707 Complex!T[] reference = fft!T(A); 708 709 RFFT!T rfft; 710 rfft.initialize(cast(int)A.length); 711 712 int N = cast(int)(A.length); 713 Complex!T[] B; 714 T[] C; 715 B.reallocBuffer(N/2+1); 716 C.reallocBuffer(N); 717 718 rfft.forwardTransform(A, B); 719 720 foreach(i; 0..N/2+1) 721 { 722 if (!approxEqual(reference[i].re, B[i].re)) 723 assert(false); 724 if (!approxEqual(reference[i].im, B[i].im)) 725 assert(false); 726 } 727 rfft.reverseTransform(B, C); 728 729 foreach(i; 0..N) 730 { 731 if (!approxEqual(A[i].re, C[i].re)) 732 assert(false); 733 if (!approxEqual(A[i].im, C[i].im)) 734 assert(false); 735 } 736 737 B.reallocBuffer(0); 738 C.reallocBuffer(0); 739 } 740 testRFFT!float([0.5f]); 741 testRFFT!float([1, 2]); 742 testRFFT!float([1, 13, 5, 0]); 743 testRFFT!float([1, 13, 5, 0, 2, 0, 4, 0]); 744 745 // test larger FFTs 746 uint seed = 1; 747 for(int bit = 4; bit < 16; ++bit) 748 { 749 int size = 1 << bit; 750 double[] sequence = new double[size]; 751 foreach(i; 0..size) 752 sequence[i] = nogc_uniform_float(-1.0f, 1.0f, random); 753 testRFFT!double(sequence); 754 } 755 }