github.com/gopherd/gonum@v0.0.4/dsp/fourier/internal/fftpack/cfft.go (about) 1 // Copyright ©2018 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This is a translation of the FFTPACK cfft functions by 6 // Paul N Swarztrauber, placed in the public domain at 7 // http://www.netlib.org/fftpack/. 8 9 package fftpack 10 11 import ( 12 "math" 13 "math/cmplx" 14 ) 15 16 // Cffti initializes the array work which is used in both Cfftf 17 // and Cfftb. the prime factorization of n together with a 18 // tabulation of the trigonometric functions are computed and 19 // stored in work. 20 // 21 // input parameter 22 // 23 // n The length of the sequence to be transformed. 24 // 25 // Output parameters: 26 // 27 // work A work array which must be dimensioned at least 4*n. 28 // the same work array can be used for both Cfftf and Cfftb 29 // as long as n remains unchanged. Different work arrays 30 // are required for different values of n. The contents of 31 // work must not be changed between calls of Cfftf or Cfftb. 32 // 33 // ifac A work array containing the factors of n. ifac must have 34 // length 15. 35 func Cffti(n int, work []float64, ifac []int) { 36 if len(work) < 4*n { 37 panic("fourier: short work") 38 } 39 if len(ifac) < 15 { 40 panic("fourier: short ifac") 41 } 42 if n == 1 { 43 return 44 } 45 cffti1(n, work[2*n:4*n], ifac[:15]) 46 } 47 48 func cffti1(n int, wa []float64, ifac []int) { 49 ntryh := [4]int{3, 4, 2, 5} 50 51 nl := n 52 nf := 0 53 54 outer: 55 for j, ntry := 0, 0; ; j++ { 56 if j < 4 { 57 ntry = ntryh[j] 58 } else { 59 ntry += 2 60 } 61 for { 62 if nl%ntry != 0 { 63 continue outer 64 } 65 66 ifac[nf+2] = ntry 67 nl /= ntry 68 nf++ 69 70 if ntry == 2 && nf != 1 { 71 for i := 1; i < nf; i++ { 72 ib := nf - i + 1 73 ifac[ib+1] = ifac[ib] 74 } 75 ifac[2] = 2 76 } 77 78 if nl == 1 { 79 break outer 80 } 81 } 82 } 83 84 ifac[0] = n 85 ifac[1] = nf 86 87 argh := 2 * math.Pi / float64(n) 88 i := 1 89 l1 := 1 90 for k1 := 0; k1 < nf; k1++ { 91 ip := ifac[k1+2] 92 ld := 0 93 l2 := l1 * ip 94 ido := n / l2 95 idot := 2*ido + 2 96 for j := 0; j < ip-1; j++ { 97 i1 := i 98 wa[i-1] = 1 99 wa[i] = 0 100 ld += l1 101 var fi float64 102 argld := float64(ld) * argh 103 for ii := 3; ii < idot; ii += 2 { 104 i += 2 105 fi++ 106 arg := fi * argld 107 wa[i-1] = math.Cos(arg) 108 wa[i] = math.Sin(arg) 109 } 110 if ip > 5 { 111 wa[i1-1] = wa[i-1] 112 wa[i1] = wa[i] 113 } 114 } 115 l1 = l2 116 } 117 } 118 119 // Cfftf computes the forward complex Discrete Fourier transform 120 // (the Fourier analysis). Equivalently, Cfftf computes the 121 // Fourier coefficients of a complex periodic sequence. The 122 // transform is defined below at output parameter c. 123 // 124 // Input parameters: 125 // 126 // n The length of the array c to be transformed. The method 127 // is most efficient when n is a product of small primes. 128 // n may change so long as different work arrays are provided. 129 // 130 // c A complex array of length n which contains the sequence 131 // to be transformed. 132 // 133 // work A real work array which must be dimensioned at least 4*n. 134 // in the program that calls Cfftf. The work array must be 135 // initialized by calling subroutine Cffti(n,work,ifac) and a 136 // different work array must be used for each different 137 // value of n. This initialization does not have to be 138 // repeated so long as n remains unchanged thus subsequent 139 // transforms can be obtained faster than the first. 140 // the same work array can be used by Cfftf and Cfftb. 141 // 142 // ifac A work array containing the factors of n. ifac must have 143 // length of at least 15. 144 // 145 // Output parameters: 146 // 147 // c for j=0, ..., n-1 148 // c[j]=the sum from k=0, ..., n-1 of 149 // c[k]*exp(-i*j*k*2*pi/n) 150 // 151 // where i=sqrt(-1) 152 // 153 // This transform is unnormalized since a call of Cfftf 154 // followed by a call of Cfftb will multiply the input 155 // sequence by n. 156 // 157 // The n elements of c are represented in n pairs of real 158 // values in r where c[j] = r[j*2]+r[j*2+1]i. 159 // 160 // work Contains results which must not be destroyed between 161 // calls of Cfftf or Cfftb. 162 // ifac Contains results which must not be destroyed between 163 // calls of Cfftf or Cfftb. 164 func Cfftf(n int, r, work []float64, ifac []int) { 165 if len(r) < 2*n { 166 panic("fourier: short sequence") 167 } 168 if len(work) < 4*n { 169 panic("fourier: short work") 170 } 171 if len(ifac) < 15 { 172 panic("fourier: short ifac") 173 } 174 if n == 1 { 175 return 176 } 177 cfft1(n, r[:2*n], work[:2*n], work[2*n:4*n], ifac[:15], -1) 178 } 179 180 // Cfftb computes the backward complex Discrete Fourier Transform 181 // (the Fourier synthesis). Equivalently, Cfftf computes the computes 182 // a complex periodic sequence from its Fourier coefficients. The 183 // transform is defined below at output parameter c. 184 // 185 // Input parameters: 186 // 187 // n The length of the array c to be transformed. The method 188 // is most efficient when n is a product of small primes. 189 // n may change so long as different work arrays are provided. 190 // 191 // c A complex array of length n which contains the sequence 192 // to be transformed. 193 // 194 // work A real work array which must be dimensioned at least 4*n. 195 // in the program that calls Cfftb. The work array must be 196 // initialized by calling subroutine Cffti(n,work,ifac) and a 197 // different work array must be used for each different 198 // value of n. This initialization does not have to be 199 // repeated so long as n remains unchanged thus subsequent 200 // transforms can be obtained faster than the first. 201 // The same work array can be used by Cfftf and Cfftb. 202 // 203 // ifac A work array containing the factors of n. ifac must have 204 // length of at least 15. 205 // 206 // Output parameters: 207 // 208 // c for j=0, ..., n-1 209 // c[j]=the sum from k=0, ..., n-1 of 210 // c[k]*exp(i*j*k*2*pi/n) 211 // 212 // where i=sqrt(-1) 213 // 214 // This transform is unnormalized since a call of Cfftf 215 // followed by a call of Cfftb will multiply the input 216 // sequence by n. 217 // 218 // The n elements of c are represented in n pairs of real 219 // values in r where c[j] = r[j*2]+r[j*2+1]i. 220 // 221 // work Contains results which must not be destroyed between 222 // calls of Cfftf or Cfftb. 223 // ifac Contains results which must not be destroyed between 224 // calls of Cfftf or Cfftb. 225 func Cfftb(n int, c, work []float64, ifac []int) { 226 if len(c) < 2*n { 227 panic("fourier: short sequence") 228 } 229 if len(work) < 4*n { 230 panic("fourier: short work") 231 } 232 if len(ifac) < 15 { 233 panic("fourier: short ifac") 234 } 235 if n == 1 { 236 return 237 } 238 cfft1(n, c[:2*n], work[:2*n], work[2*n:4*n], ifac[:15], 1) 239 } 240 241 // cfft1 implements cfftf1 and cfftb1 depending on sign. 242 func cfft1(n int, c, ch, wa []float64, ifac []int, sign float64) { 243 nf := ifac[1] 244 na := false 245 l1 := 1 246 iw := 0 247 248 for k1 := 1; k1 <= nf; k1++ { 249 ip := ifac[k1+1] 250 l2 := ip * l1 251 ido := n / l2 252 idot := 2 * ido 253 idl1 := idot * l1 254 255 switch ip { 256 case 4: 257 ix2 := iw + idot 258 ix3 := ix2 + idot 259 if na { 260 pass4(idot, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:], sign) 261 } else { 262 pass4(idot, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:], sign) 263 } 264 na = !na 265 case 2: 266 if na { 267 pass2(idot, l1, ch, c, wa[iw:], sign) 268 } else { 269 pass2(idot, l1, c, ch, wa[iw:], sign) 270 } 271 na = !na 272 case 3: 273 ix2 := iw + idot 274 if na { 275 pass3(idot, l1, ch, c, wa[iw:], wa[ix2:], sign) 276 } else { 277 pass3(idot, l1, c, ch, wa[iw:], wa[ix2:], sign) 278 } 279 na = !na 280 case 5: 281 ix2 := iw + idot 282 ix3 := ix2 + idot 283 ix4 := ix3 + idot 284 if na { 285 pass5(idot, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:], sign) 286 } else { 287 pass5(idot, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:], sign) 288 } 289 na = !na 290 default: 291 var nac bool 292 if na { 293 nac = pass(idot, ip, l1, idl1, ch, ch, ch, c, c, wa[iw:], sign) 294 } else { 295 nac = pass(idot, ip, l1, idl1, c, c, c, ch, ch, wa[iw:], sign) 296 } 297 if nac { 298 na = !na 299 } 300 } 301 302 l1 = l2 303 iw += (ip - 1) * idot 304 } 305 306 if na { 307 for i := 0; i < 2*n; i++ { 308 c[i] = ch[i] 309 } 310 } 311 } 312 313 // pass2 implements passf2 and passb2 depending on sign. 314 func pass2(ido, l1 int, cc, ch, wa1 []float64, sign float64) { 315 cc3 := newThreeArray(ido, 2, l1, cc) 316 ch3 := newThreeArray(ido, l1, 2, ch) 317 318 if ido <= 2 { 319 for k := 0; k < l1; k++ { 320 ch3.setCmplx(0, k, 0, cc3.atCmplx(0, 0, k)+cc3.atCmplx(0, 1, k)) 321 ch3.setCmplx(0, k, 1, cc3.atCmplx(0, 0, k)-cc3.atCmplx(0, 1, k)) 322 } 323 return 324 } 325 for k := 0; k < l1; k++ { 326 for i := 1; i < ido; i += 2 { 327 ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+cc3.atCmplx(i-1, 1, k)) 328 t2 := cc3.atCmplx(i-1, 0, k) - cc3.atCmplx(i-1, 1, k) 329 ch3.setCmplx(i-1, k, 1, complex(wa1[i-1], sign*wa1[i])*t2) 330 } 331 } 332 } 333 334 // pass3 implements passf3 and passb3 depending on sign. 335 func pass3(ido, l1 int, cc, ch, wa1, wa2 []float64, sign float64) { 336 const ( 337 taur = -0.5 338 taui = 0.866025403784439 // sqrt(3)/2 339 ) 340 341 cc3 := newThreeArray(ido, 3, l1, cc) 342 ch3 := newThreeArray(ido, l1, 3, ch) 343 344 if ido == 2 { 345 for k := 0; k < l1; k++ { 346 t2 := cc3.atCmplx(0, 1, k) + cc3.atCmplx(0, 2, k) 347 ch3.setCmplx(0, k, 0, cc3.atCmplx(0, 0, k)+t2) 348 349 c2 := cc3.atCmplx(0, 0, k) + scale(taur, t2) 350 c3 := cmplx.Conj(swap(scale(sign*taui, cc3.atCmplx(0, 1, k)-cc3.atCmplx(0, 2, k)))) 351 ch3.setCmplx(0, k, 1, c2-c3) 352 ch3.setCmplx(0, k, 2, c2+c3) 353 } 354 return 355 } 356 for k := 0; k < l1; k++ { 357 for i := 1; i < ido; i += 2 { 358 t2 := cc3.atCmplx(i-1, 1, k) + cc3.atCmplx(i-1, 2, k) 359 ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+t2) 360 361 c2 := cc3.atCmplx(i-1, 0, k) + scale(taur, t2) 362 c3 := cmplx.Conj(swap(scale(sign*taui, cc3.atCmplx(i-1, 1, k)-cc3.atCmplx(i-1, 2, k)))) 363 d2 := c2 - c3 364 d3 := c2 + c3 365 ch3.setCmplx(i-1, k, 1, complex(wa1[i-1], sign*wa1[i])*d2) 366 ch3.setCmplx(i-1, k, 2, complex(wa2[i-1], sign*wa2[i])*d3) 367 } 368 } 369 } 370 371 // pass4 implements passf4 and passb4 depending on sign. 372 func pass4(ido, l1 int, cc, ch, wa1, wa2, wa3 []float64, sign float64) { 373 cc3 := newThreeArray(ido, 4, l1, cc) 374 ch3 := newThreeArray(ido, l1, 4, ch) 375 376 if ido == 2 { 377 for k := 0; k < l1; k++ { 378 t1 := cc3.atCmplx(0, 0, k) - cc3.atCmplx(0, 2, k) 379 t2 := cc3.atCmplx(0, 0, k) + cc3.atCmplx(0, 2, k) 380 t3 := cc3.atCmplx(0, 1, k) + cc3.atCmplx(0, 3, k) 381 t4 := cmplx.Conj(swap(scale(sign, cc3.atCmplx(0, 3, k)-cc3.atCmplx(0, 1, k)))) 382 383 ch3.setCmplx(0, k, 0, t2+t3) 384 ch3.setCmplx(0, k, 1, t1+t4) 385 ch3.setCmplx(0, k, 2, t2-t3) 386 ch3.setCmplx(0, k, 3, t1-t4) 387 } 388 return 389 } 390 for k := 0; k < l1; k++ { 391 for i := 1; i < ido; i += 2 { 392 t1 := cc3.atCmplx(i-1, 0, k) - cc3.atCmplx(i-1, 2, k) 393 t2 := cc3.atCmplx(i-1, 0, k) + cc3.atCmplx(i-1, 2, k) 394 t3 := cc3.atCmplx(i-1, 1, k) + cc3.atCmplx(i-1, 3, k) 395 t4 := cmplx.Conj(swap(scale(sign, cc3.atCmplx(i-1, 3, k)-cc3.atCmplx(i-1, 1, k)))) 396 ch3.setCmplx(i-1, k, 0, t2+t3) 397 398 c2 := t1 + t4 399 c3 := t2 - t3 400 c4 := t1 - t4 401 ch3.setCmplx(i-1, k, 1, complex(wa1[i-1], sign*wa1[i])*c2) 402 ch3.setCmplx(i-1, k, 2, complex(wa2[i-1], sign*wa2[i])*c3) 403 ch3.setCmplx(i-1, k, 3, complex(wa3[i-1], sign*wa3[i])*c4) 404 } 405 } 406 } 407 408 // pass5 implements passf5 and passb5 depending on sign. 409 func pass5(ido, l1 int, cc, ch, wa1, wa2, wa3, wa4 []float64, sign float64) { 410 const ( 411 tr11 = 0.309016994374947 412 ti11 = 0.951056516295154 413 tr12 = -0.809016994374947 414 ti12 = 0.587785252292473 415 ) 416 417 cc3 := newThreeArray(ido, 5, l1, cc) 418 ch3 := newThreeArray(ido, l1, 5, ch) 419 420 if ido == 2 { 421 for k := 0; k < l1; k++ { 422 t2 := cc3.atCmplx(0, 1, k) + cc3.atCmplx(0, 4, k) 423 t3 := cc3.atCmplx(0, 2, k) + cc3.atCmplx(0, 3, k) 424 t4 := cc3.atCmplx(0, 2, k) - cc3.atCmplx(0, 3, k) 425 t5 := cc3.atCmplx(0, 1, k) - cc3.atCmplx(0, 4, k) 426 ch3.setCmplx(0, k, 0, cc3.atCmplx(0, 0, k)+t2+t3) 427 428 c2 := cc3.atCmplx(0, 0, k) + scale(tr11, t2) + scale(tr12, t3) 429 c3 := cc3.atCmplx(0, 0, k) + scale(tr12, t2) + scale(tr11, t3) 430 c4 := cmplx.Conj(swap(scale(sign, scale(ti12, t5)-scale(ti11, t4)))) 431 c5 := cmplx.Conj(swap(scale(sign, scale(ti11, t5)+scale(ti12, t4)))) 432 ch3.setCmplx(0, k, 1, c2-c5) 433 ch3.setCmplx(0, k, 2, c3-c4) 434 ch3.setCmplx(0, k, 3, c3+c4) 435 ch3.setCmplx(0, k, 4, c2+c5) 436 } 437 return 438 } 439 for k := 0; k < l1; k++ { 440 for i := 1; i < ido; i += 2 { 441 t2 := cc3.atCmplx(i-1, 1, k) + cc3.atCmplx(i-1, 4, k) 442 t3 := cc3.atCmplx(i-1, 2, k) + cc3.atCmplx(i-1, 3, k) 443 t4 := cc3.atCmplx(i-1, 2, k) - cc3.atCmplx(i-1, 3, k) 444 t5 := cc3.atCmplx(i-1, 1, k) - cc3.atCmplx(i-1, 4, k) 445 ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+t2+t3) 446 447 c2 := cc3.atCmplx(i-1, 0, k) + scale(tr11, t2) + scale(tr12, t3) 448 c3 := cc3.atCmplx(i-1, 0, k) + scale(tr12, t2) + scale(tr11, t3) 449 c4 := cmplx.Conj(swap(scale(sign, scale(ti12, t5)-scale(ti11, t4)))) 450 c5 := cmplx.Conj(swap(scale(sign, scale(ti11, t5)+scale(ti12, t4)))) 451 d2 := c2 - c5 452 d3 := c3 - c4 453 d4 := c3 + c4 454 d5 := c2 + c5 455 ch3.setCmplx(i-1, k, 1, complex(wa1[i-1], sign*wa1[i])*d2) 456 ch3.setCmplx(i-1, k, 2, complex(wa2[i-1], sign*wa2[i])*d3) 457 ch3.setCmplx(i-1, k, 3, complex(wa3[i-1], sign*wa3[i])*d4) 458 ch3.setCmplx(i-1, k, 4, complex(wa4[i-1], sign*wa4[i])*d5) 459 } 460 } 461 } 462 463 // pass implements passf and passb depending on sign. 464 func pass(ido, ip, l1, idl1 int, cc, c1, c2, ch, ch2, wa []float64, sign float64) (nac bool) { 465 cc3 := newThreeArray(ido, ip, l1, cc) 466 c13 := newThreeArray(ido, l1, ip, c1) 467 ch3 := newThreeArray(ido, l1, ip, ch) 468 c2m := newTwoArray(idl1, ip, c2) 469 ch2m := newTwoArray(idl1, ip, ch2) 470 471 idot := ido / 2 472 ipph := (ip + 1) / 2 473 idp := ip * ido 474 475 if ido < l1 { 476 for j := 1; j < ipph; j++ { 477 jc := ip - j 478 for i := 0; i < ido; i++ { 479 for k := 0; k < l1; k++ { 480 ch3.set(i, k, j, cc3.at(i, j, k)+cc3.at(i, jc, k)) 481 ch3.set(i, k, jc, cc3.at(i, j, k)-cc3.at(i, jc, k)) 482 } 483 } 484 } 485 for i := 0; i < ido; i++ { 486 for k := 0; k < l1; k++ { 487 ch3.set(i, k, 0, cc3.at(i, 0, k)) 488 } 489 } 490 } else { 491 for j := 1; j < ipph; j++ { 492 jc := ip - j 493 for k := 0; k < l1; k++ { 494 for i := 0; i < ido; i++ { 495 ch3.set(i, k, j, cc3.at(i, j, k)+cc3.at(i, jc, k)) 496 ch3.set(i, k, jc, cc3.at(i, j, k)-cc3.at(i, jc, k)) 497 } 498 } 499 } 500 for k := 0; k < l1; k++ { 501 for i := 0; i < ido; i++ { 502 ch3.set(i, k, 0, cc3.at(i, 0, k)) 503 } 504 } 505 } 506 507 idl := 1 - ido 508 inc := 0 509 for l := 1; l < ipph; l++ { 510 lc := ip - l 511 idl += ido 512 for ik := 0; ik < idl1; ik++ { 513 c2m.set(ik, l, ch2m.at(ik, 0)+wa[idl-1]*ch2m.at(ik, 1)) 514 c2m.set(ik, lc, sign*wa[idl]*ch2m.at(ik, ip-1)) 515 } 516 idlj := idl 517 inc += ido 518 for j := 2; j < ipph; j++ { 519 jc := ip - j 520 idlj += inc 521 if idlj > idp { 522 idlj -= idp 523 } 524 war := wa[idlj-1] 525 wai := wa[idlj] 526 for ik := 0; ik < idl1; ik++ { 527 c2m.add(ik, l, war*ch2m.at(ik, j)) 528 c2m.add(ik, lc, sign*wai*ch2m.at(ik, jc)) 529 } 530 } 531 } 532 533 for j := 1; j < ipph; j++ { 534 for ik := 0; ik < idl1; ik++ { 535 ch2m.add(ik, 0, ch2m.at(ik, j)) 536 } 537 } 538 539 for j := 1; j < ipph; j++ { 540 jc := ip - j 541 for ik := 1; ik < idl1; ik += 2 { 542 ch2m.setCmplx(ik-1, j, c2m.atCmplx(ik-1, j)-cmplx.Conj(swap(c2m.atCmplx(ik-1, jc)))) 543 ch2m.setCmplx(ik-1, jc, c2m.atCmplx(ik-1, j)+cmplx.Conj(swap(c2m.atCmplx(ik-1, jc)))) 544 } 545 } 546 547 if ido == 2 { 548 return true 549 } 550 551 for ik := 0; ik < idl1; ik++ { 552 c2m.set(ik, 0, ch2m.at(ik, 0)) 553 } 554 555 for j := 1; j < ip; j++ { 556 for k := 0; k < l1; k++ { 557 c13.setCmplx(0, k, j, ch3.atCmplx(0, k, j)) 558 } 559 } 560 561 if idot > l1 { 562 idj := 1 - ido 563 for j := 1; j < ip; j++ { 564 idj += ido 565 for k := 0; k < l1; k++ { 566 idij := idj 567 for i := 3; i < ido; i += 2 { 568 idij += 2 569 c13.setCmplx(i-1, k, j, complex(wa[idij-1], sign*wa[idij])*ch3.atCmplx(i-1, k, j)) 570 } 571 } 572 } 573 574 return false 575 } 576 577 idij := -1 578 for j := 1; j < ip; j++ { 579 idij += 2 580 for i := 3; i < ido; i += 2 { 581 idij += 2 582 for k := 0; k < l1; k++ { 583 c13.setCmplx(i-1, k, j, complex(wa[idij-1], sign*wa[idij])*ch3.atCmplx(i-1, k, j)) 584 } 585 } 586 } 587 return false 588 }