github.com/gopherd/gonum@v0.0.4/dsp/fourier/internal/fftpack/rfft.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 rfft 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  // Rffti initializes the array work which is used in both Rfftf
    17  // and Rfftb. 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 2*n.
    28  //         The same work array can be used for both Rfftf and Rfftb
    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 Rfftf or Rfftb.
    32  //
    33  //  ifac   A work array containing the factors of n. ifac must have
    34  //         length of at least 15.
    35  func Rffti(n int, work []float64, ifac []int) {
    36  	if len(work) < 2*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  	rffti1(n, work[n:2*n], ifac[:15])
    46  }
    47  
    48  func rffti1(n int, wa []float64, ifac []int) {
    49  	ntryh := [4]int{4, 2, 3, 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  	if nf == 1 {
    87  		return
    88  	}
    89  	argh := 2 * math.Pi / float64(n)
    90  
    91  	is := 0
    92  	l1 := 1
    93  	for k1 := 0; k1 < nf-1; k1++ {
    94  		ip := ifac[k1+2]
    95  		ld := 0
    96  		l2 := l1 * ip
    97  		ido := n / l2
    98  		for j := 0; j < ip-1; j++ {
    99  			ld += l1
   100  			i := is
   101  			fi := 0.0
   102  			argld := float64(ld) * argh
   103  			for ii := 2; ii < ido; ii += 2 {
   104  				fi++
   105  				arg := fi * argld
   106  				wa[i] = math.Cos(arg)
   107  				wa[i+1] = math.Sin(arg)
   108  				i += 2
   109  			}
   110  			is += ido
   111  		}
   112  		l1 = l2
   113  	}
   114  }
   115  
   116  // Rfftf computes the Fourier coefficients of a real perodic sequence
   117  // (Fourier analysis). The transform is defined below at output
   118  // parameter r.
   119  //
   120  //  Input parameters:
   121  //
   122  //  n      The length of the array r to be transformed. The method
   123  //         is most efficient when n is a product of small primes.
   124  //         n may change so long as different work arrays are provided.
   125  //
   126  //  r      A real array of length n which contains the sequence
   127  //         to be transformed.
   128  //
   129  //  work   a work array which must be dimensioned at least 2*n.
   130  //         in the program that calls Rfftf. the work array must be
   131  //         initialized by calling subroutine rffti(n,work,ifac) and a
   132  //         different work array must be used for each different
   133  //         value of n. This initialization does not have to be
   134  //         repeated so long as n remains unchanged. Thus subsequent
   135  //         transforms can be obtained faster than the first.
   136  //         The same work array can be used by Rfftf and Rfftb.
   137  //
   138  //  ifac   A work array containing the factors of n. ifac must have
   139  //         length of at least 15.
   140  //
   141  //  Output parameters:
   142  //
   143  //  r      r[0] = the sum from i=0 to i=n-1 of r[i]
   144  //
   145  //         if n is even set l=n/2, if n is odd set l = (n+1)/2
   146  //           then for k = 1, ..., l-1
   147  //             r[2*k-1] = the sum from i = 0 to i = n-1 of
   148  //               r[i]*cos(k*i*2*pi/n)
   149  //             r[2*k] = the sum from i = 0 to i = n-1 of
   150  //               -r[i]*sin(k*i*2*pi/n)
   151  //
   152  //         if n is even
   153  //           r[n-1] = the sum from i = 0 to i = n-1 of
   154  //             (-1)^i*r[i]
   155  //
   156  //  This transform is unnormalized since a call of Rfftf
   157  //  followed by a call of Rfftb will multiply the input
   158  //  sequence by n.
   159  //
   160  //  work   contains results which must not be destroyed between
   161  //         calls of Rfftf or Rfftb.
   162  //  ifac   contains results which must not be destroyed between
   163  //         calls of Rfftf or Rfftb.
   164  func Rfftf(n int, r, work []float64, ifac []int) {
   165  	if len(r) < n {
   166  		panic("fourier: short sequence")
   167  	}
   168  	if len(work) < 2*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  	rfftf1(n, r[:n], work[:n], work[n:2*n], ifac[:15])
   178  }
   179  
   180  func rfftf1(n int, c, ch, wa []float64, ifac []int) {
   181  	nf := ifac[1]
   182  	na := true
   183  	l2 := n
   184  	iw := n - 1
   185  
   186  	for k1 := 1; k1 <= nf; k1++ {
   187  		kh := nf - k1
   188  		ip := ifac[kh+2]
   189  		l1 := l2 / ip
   190  		ido := n / l2
   191  		idl1 := ido * l1
   192  		iw -= (ip - 1) * ido
   193  		na = !na
   194  
   195  		switch ip {
   196  		case 4:
   197  			ix2 := iw + ido
   198  			ix3 := ix2 + ido
   199  			if na {
   200  				radf4(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:])
   201  			} else {
   202  				radf4(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:])
   203  			}
   204  		case 2:
   205  			if na {
   206  				radf2(ido, l1, ch, c, wa[iw:])
   207  			} else {
   208  				radf2(ido, l1, c, ch, wa[iw:])
   209  			}
   210  		case 3:
   211  			ix2 := iw + ido
   212  			if na {
   213  				radf3(ido, l1, ch, c, wa[iw:], wa[ix2:])
   214  			} else {
   215  				radf3(ido, l1, c, ch, wa[iw:], wa[ix2:])
   216  			}
   217  		case 5:
   218  			ix2 := iw + ido
   219  			ix3 := ix2 + ido
   220  			ix4 := ix3 + ido
   221  			if na {
   222  				radf5(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:])
   223  			} else {
   224  				radf5(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:])
   225  			}
   226  		default:
   227  			if ido == 1 {
   228  				na = !na
   229  			}
   230  			if na {
   231  				radfg(ido, ip, l1, idl1, ch, ch, ch, c, c, wa[iw:])
   232  				na = false
   233  			} else {
   234  				radfg(ido, ip, l1, idl1, c, c, c, ch, ch, wa[iw:])
   235  				na = true
   236  			}
   237  		}
   238  
   239  		l2 = l1
   240  	}
   241  
   242  	if na {
   243  		return
   244  	}
   245  	for i := 0; i < n; i++ {
   246  		c[i] = ch[i]
   247  	}
   248  }
   249  
   250  func radf2(ido, l1 int, cc, ch, wa1 []float64) {
   251  	cc3 := newThreeArray(ido, l1, 2, cc)
   252  	ch3 := newThreeArray(ido, 2, l1, ch)
   253  
   254  	for k := 0; k < l1; k++ {
   255  		ch3.set(0, 0, k, cc3.at(0, k, 0)+cc3.at(0, k, 1))
   256  		ch3.set(ido-1, 1, k, cc3.at(0, k, 0)-cc3.at(0, k, 1))
   257  	}
   258  	if ido < 2 {
   259  		return
   260  	}
   261  	if ido > 2 {
   262  		idp2 := ido + 1
   263  		for k := 0; k < l1; k++ {
   264  			for i := 2; i < ido; i += 2 {
   265  				ic := idp2 - (i + 1)
   266  
   267  				t2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1)
   268  				ch3.setCmplx(i-1, 0, k, cc3.atCmplx(i-1, k, 0)+t2)
   269  
   270  				// This is left as conj(z1)-conj(z2) rather than conj(z1-z2)
   271  				// to retain current signed zero behaviour.
   272  				ch3.setCmplx(ic-1, 1, k, cmplx.Conj(cc3.atCmplx(i-1, k, 0))-cmplx.Conj(t2))
   273  			}
   274  		}
   275  		if ido%2 == 1 {
   276  			return
   277  		}
   278  	}
   279  	for k := 0; k < l1; k++ {
   280  		ch3.set(0, 1, k, -cc3.at(ido-1, k, 1))
   281  		ch3.set(ido-1, 0, k, cc3.at(ido-1, k, 0))
   282  	}
   283  }
   284  
   285  func radf3(ido, l1 int, cc, ch, wa1, wa2 []float64) {
   286  	const (
   287  		taur = -0.5
   288  		taui = 0.866025403784439 // sqrt(3)/2
   289  	)
   290  
   291  	cc3 := newThreeArray(ido, l1, 3, cc)
   292  	ch3 := newThreeArray(ido, 3, l1, ch)
   293  
   294  	for k := 0; k < l1; k++ {
   295  		cr2 := cc3.at(0, k, 1) + cc3.at(0, k, 2)
   296  		ch3.set(0, 0, k, cc3.at(0, k, 0)+cr2)
   297  		ch3.set(0, 2, k, taui*(cc3.at(0, k, 2)-cc3.at(0, k, 1)))
   298  		ch3.set(ido-1, 1, k, cc3.at(0, k, 0)+taur*cr2)
   299  	}
   300  	if ido < 2 {
   301  		return
   302  	}
   303  	idp2 := ido + 1
   304  	for k := 0; k < l1; k++ {
   305  		for i := 2; i < ido; i += 2 {
   306  			ic := idp2 - (i + 1)
   307  
   308  			d2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1)
   309  			d3 := complex(wa2[i-2], -wa2[i-1]) * cc3.atCmplx(i-1, k, 2)
   310  			c2 := d2 + d3
   311  			ch3.setCmplx(i-1, 0, k, cc3.atCmplx(i-1, k, 0)+c2)
   312  
   313  			t2 := cc3.atCmplx(i-1, k, 0) + scale(taur, c2)
   314  			t3 := scale(taui, cmplx.Conj(swap(d2-d3)))
   315  			ch3.setCmplx(i-1, 2, k, t2+t3)
   316  			ch3.setCmplx(ic-1, 1, k, cmplx.Conj(t2-t3))
   317  		}
   318  	}
   319  }
   320  
   321  func radf4(ido, l1 int, cc, ch, wa1, wa2, wa3 []float64) {
   322  	const hsqt2 = math.Sqrt2 / 2
   323  
   324  	cc3 := newThreeArray(ido, l1, 4, cc)
   325  	ch3 := newThreeArray(ido, 4, l1, ch)
   326  
   327  	for k := 0; k < l1; k++ {
   328  		tr1 := cc3.at(0, k, 1) + cc3.at(0, k, 3)
   329  		tr2 := cc3.at(0, k, 0) + cc3.at(0, k, 2)
   330  		ch3.set(0, 0, k, tr1+tr2)
   331  		ch3.set(ido-1, 3, k, tr2-tr1)
   332  		ch3.set(ido-1, 1, k, cc3.at(0, k, 0)-cc3.at(0, k, 2))
   333  		ch3.set(0, 2, k, cc3.at(0, k, 3)-cc3.at(0, k, 1))
   334  	}
   335  	if ido < 2 {
   336  		return
   337  	}
   338  	if ido > 2 {
   339  		idp2 := ido + 1
   340  		for k := 0; k < l1; k++ {
   341  			for i := 2; i < ido; i += 2 {
   342  				ic := idp2 - (i + 1)
   343  
   344  				c2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1)
   345  				c3 := complex(wa2[i-2], -wa2[i-1]) * cc3.atCmplx(i-1, k, 2)
   346  				c4 := complex(wa3[i-2], -wa3[i-1]) * cc3.atCmplx(i-1, k, 3)
   347  				t1 := c2 + c4
   348  				t2 := cc3.atCmplx(i-1, k, 0) + c3
   349  				t3 := cc3.atCmplx(i-1, k, 0) - c3
   350  				t4 := cmplx.Conj(c4 - c2)
   351  				ch3.setCmplx(i-1, 0, k, t1+t2)
   352  				ch3.setCmplx(ic-1, 3, k, cmplx.Conj(t2-t1))
   353  				ch3.setCmplx(i-1, 2, k, swap(t4)+t3)
   354  				ch3.setCmplx(ic-1, 1, k, cmplx.Conj(t3-swap(t4)))
   355  			}
   356  		}
   357  
   358  		if ido%2 == 1 {
   359  			return
   360  		}
   361  	}
   362  	for k := 0; k < l1; k++ {
   363  		ti1 := -hsqt2 * (cc3.at(ido-1, k, 1) + cc3.at(ido-1, k, 3))
   364  		tr1 := hsqt2 * (cc3.at(ido-1, k, 1) - cc3.at(ido-1, k, 3))
   365  		ch3.set(ido-1, 0, k, tr1+cc3.at(ido-1, k, 0))
   366  		ch3.set(ido-1, 2, k, cc3.at(ido-1, k, 0)-tr1)
   367  		ch3.set(0, 1, k, ti1-cc3.at(ido-1, k, 2))
   368  		ch3.set(0, 3, k, ti1+cc3.at(ido-1, k, 2))
   369  	}
   370  }
   371  
   372  func radf5(ido, l1 int, cc, ch, wa1, wa2, wa3, wa4 []float64) {
   373  	const (
   374  		tr11 = 0.309016994374947
   375  		ti11 = 0.951056516295154
   376  		tr12 = -0.809016994374947
   377  		ti12 = 0.587785252292473
   378  	)
   379  
   380  	cc3 := newThreeArray(ido, l1, 5, cc)
   381  	ch3 := newThreeArray(ido, 5, l1, ch)
   382  
   383  	for k := 0; k < l1; k++ {
   384  		cr2 := cc3.at(0, k, 4) + cc3.at(0, k, 1)
   385  		cr3 := cc3.at(0, k, 3) + cc3.at(0, k, 2)
   386  		ci4 := cc3.at(0, k, 3) - cc3.at(0, k, 2)
   387  		ci5 := cc3.at(0, k, 4) - cc3.at(0, k, 1)
   388  		ch3.set(0, 0, k, cc3.at(0, k, 0)+cr2+cr3)
   389  		ch3.set(ido-1, 1, k, cc3.at(0, k, 0)+tr11*cr2+tr12*cr3)
   390  		ch3.set(0, 2, k, ti11*ci5+ti12*ci4)
   391  		ch3.set(ido-1, 3, k, cc3.at(0, k, 0)+tr12*cr2+tr11*cr3)
   392  		ch3.set(0, 4, k, ti12*ci5-ti11*ci4)
   393  	}
   394  
   395  	if ido < 2 {
   396  		return
   397  	}
   398  	idp2 := ido + 1
   399  	for k := 0; k < l1; k++ {
   400  		for i := 2; i < ido; i += 2 {
   401  			ic := idp2 - (i + 1)
   402  
   403  			d2 := complex(wa1[i-2], -wa1[i-1]) * cc3.atCmplx(i-1, k, 1)
   404  			d3 := complex(wa2[i-2], -wa2[i-1]) * cc3.atCmplx(i-1, k, 2)
   405  			d4 := complex(wa3[i-2], -wa3[i-1]) * cc3.atCmplx(i-1, k, 3)
   406  			d5 := complex(wa4[i-2], -wa4[i-1]) * cc3.atCmplx(i-1, k, 4)
   407  			c2 := d2 + d5
   408  			c3 := d3 + d4
   409  			c4 := cmplx.Conj(swap(d3 - d4))
   410  			c5 := cmplx.Conj(swap(d2 - d5))
   411  			ch3.setCmplx(i-1, 0, k, cc3.atCmplx(i-1, k, 0)+c2+c3)
   412  
   413  			t2 := cc3.atCmplx(i-1, k, 0) + scale(tr11, c2) + scale(tr12, c3)
   414  			t3 := cc3.atCmplx(i-1, k, 0) + scale(tr12, c2) + scale(tr11, c3)
   415  			t4 := scale(ti12, c5) - scale(ti11, c4)
   416  			t5 := scale(ti11, c5) + scale(ti12, c4)
   417  			ch3.setCmplx(ic-1, 1, k, cmplx.Conj(t2-t5))
   418  			ch3.setCmplx(i-1, 2, k, t2+t5)
   419  			ch3.setCmplx(ic-1, 3, k, cmplx.Conj(t3-t4))
   420  			ch3.setCmplx(i-1, 4, k, t3+t4)
   421  		}
   422  	}
   423  }
   424  
   425  func radfg(ido, ip, l1, idl1 int, cc, c1, c2, ch, ch2, wa []float64) {
   426  	cc3 := newThreeArray(ido, ip, l1, cc)
   427  	c13 := newThreeArray(ido, l1, ip, c1)
   428  	ch3 := newThreeArray(ido, l1, ip, ch)
   429  	c2m := newTwoArray(idl1, ip, c2)
   430  	ch2m := newTwoArray(idl1, ip, ch2)
   431  
   432  	arg := 2 * math.Pi / float64(ip)
   433  	dcp := math.Cos(arg)
   434  	dsp := math.Sin(arg)
   435  	ipph := (ip + 1) / 2
   436  	nbd := (ido - 1) / 2
   437  
   438  	if ido == 1 {
   439  		for ik := 0; ik < idl1; ik++ {
   440  			c2m.set(ik, 0, ch2m.at(ik, 0))
   441  		}
   442  	} else {
   443  		for ik := 0; ik < idl1; ik++ {
   444  			ch2m.set(ik, 0, c2m.at(ik, 0))
   445  		}
   446  		for j := 1; j < ip; j++ {
   447  			for k := 0; k < l1; k++ {
   448  				ch3.set(0, k, j, c13.at(0, k, j))
   449  			}
   450  		}
   451  
   452  		is := -ido - 1
   453  		if nbd > l1 {
   454  			for j := 1; j < ip; j++ {
   455  				is += ido
   456  				for k := 0; k < l1; k++ {
   457  					idij := is
   458  					for i := 2; i < ido; i += 2 {
   459  						idij += 2
   460  						ch3.setCmplx(i-1, k, j, complex(wa[idij-1], -wa[idij])*c13.atCmplx(i-1, k, j))
   461  					}
   462  				}
   463  			}
   464  		} else {
   465  			for j := 1; j < ip; j++ {
   466  				is += ido
   467  				idij := is
   468  				for i := 2; i < ido; i += 2 {
   469  					idij += 2
   470  					for k := 0; k < l1; k++ {
   471  						ch3.setCmplx(i-1, k, j, complex(wa[idij-1], -wa[idij])*c13.atCmplx(i-1, k, j))
   472  					}
   473  				}
   474  			}
   475  		}
   476  		if nbd < l1 {
   477  			for j := 1; j < ipph; j++ {
   478  				jc := ip - j
   479  				for i := 2; i < ido; i += 2 {
   480  					for k := 0; k < l1; k++ {
   481  						c13.setCmplx(i-1, k, j, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc))
   482  						c13.setCmplx(i-1, k, jc, cmplx.Conj(swap(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc))))
   483  					}
   484  				}
   485  			}
   486  		} else {
   487  			for j := 1; j < ipph; j++ {
   488  				jc := ip - j
   489  				for k := 0; k < l1; k++ {
   490  					for i := 2; i < ido; i += 2 {
   491  						c13.setCmplx(i-1, k, j, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc))
   492  						c13.setCmplx(i-1, k, jc, cmplx.Conj(swap(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc))))
   493  					}
   494  				}
   495  			}
   496  		}
   497  	}
   498  
   499  	for j := 1; j < ipph; j++ {
   500  		jc := ip - j
   501  		for k := 0; k < l1; k++ {
   502  			c13.set(0, k, j, ch3.at(0, k, j)+ch3.at(0, k, jc))
   503  			c13.set(0, k, jc, ch3.at(0, k, jc)-ch3.at(0, k, j))
   504  		}
   505  	}
   506  	ar1 := 1.0
   507  	ai1 := 0.0
   508  	for l := 1; l < ipph; l++ {
   509  		lc := ip - l
   510  		ar1h := dcp*ar1 - dsp*ai1
   511  		ai1 = dcp*ai1 + dsp*ar1
   512  		ar1 = ar1h
   513  		for ik := 0; ik < idl1; ik++ {
   514  			ch2m.set(ik, l, c2m.at(ik, 0)+ar1*c2m.at(ik, 1))
   515  			ch2m.set(ik, lc, ai1*c2m.at(ik, ip-1))
   516  		}
   517  		dc2 := ar1
   518  		ds2 := ai1
   519  		ar2 := ar1
   520  		ai2 := ai1
   521  		for j := 2; j < ipph; j++ {
   522  			jc := ip - j
   523  			ar2h := dc2*ar2 - ds2*ai2
   524  			ai2 = dc2*ai2 + ds2*ar2
   525  			ar2 = ar2h
   526  			for ik := 0; ik < idl1; ik++ {
   527  				ch2m.add(ik, l, ar2*c2m.at(ik, j))
   528  				ch2m.add(ik, lc, ai2*c2m.at(ik, jc))
   529  			}
   530  		}
   531  	}
   532  	for j := 1; j < ipph; j++ {
   533  		for ik := 0; ik < idl1; ik++ {
   534  			ch2m.add(ik, 0, c2m.at(ik, j))
   535  		}
   536  	}
   537  
   538  	if ido < l1 {
   539  		for i := 0; i < ido; i++ {
   540  			for k := 0; k < l1; k++ {
   541  				cc3.set(i, 0, k, ch3.at(i, k, 0))
   542  			}
   543  		}
   544  	} else {
   545  		for k := 0; k < l1; k++ {
   546  			for i := 0; i < ido; i++ {
   547  				cc3.set(i, 0, k, ch3.at(i, k, 0))
   548  			}
   549  		}
   550  	}
   551  	for j := 1; j < ipph; j++ {
   552  		jc := ip - j
   553  		j2 := 2 * j
   554  		for k := 0; k < l1; k++ {
   555  			cc3.set(ido-1, j2-1, k, ch3.at(0, k, j))
   556  			cc3.set(0, j2, k, ch3.at(0, k, jc))
   557  		}
   558  	}
   559  
   560  	if ido == 1 {
   561  		return
   562  	}
   563  	if nbd < l1 {
   564  		for j := 1; j < ipph; j++ {
   565  			jc := ip - j
   566  			j2 := 2 * j
   567  			for i := 2; i < ido; i += 2 {
   568  				ic := ido - i
   569  				for k := 0; k < l1; k++ {
   570  					cc3.setCmplx(i-1, j2, k, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc))
   571  					cc3.setCmplx(ic-1, j2-1, k, cmplx.Conj(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc)))
   572  				}
   573  			}
   574  		}
   575  		return
   576  	}
   577  	for j := 1; j < ipph; j++ {
   578  		jc := ip - j
   579  		j2 := 2 * j
   580  		for k := 0; k < l1; k++ {
   581  			for i := 2; i < ido; i += 2 {
   582  				ic := ido - i
   583  
   584  				cc3.setCmplx(i-1, j2, k, ch3.atCmplx(i-1, k, j)+ch3.atCmplx(i-1, k, jc))
   585  				cc3.setCmplx(ic-1, j2-1, k, cmplx.Conj(ch3.atCmplx(i-1, k, j)-ch3.atCmplx(i-1, k, jc)))
   586  			}
   587  		}
   588  	}
   589  }
   590  
   591  // Rfftb computes the real perodic sequence from its Fourier
   592  // coefficients (Fourier synthesis). The transform is defined
   593  // below at output parameter r.
   594  //
   595  //  Input parameters
   596  //
   597  //  n      The length of the array r to be transformed. The method
   598  //         is most efficient when n is a product of small primes.
   599  //         n may change so long as different work arrays are provided.
   600  //
   601  //  r      A real array of length n which contains the sequence
   602  //         to be transformed.
   603  //
   604  //  work   A work array which must be dimensioned at least 2*n.
   605  //         in the program that calls Rfftb. The work array must be
   606  //         initialized by calling subroutine rffti(n,work,ifac) and a
   607  //         different work array must be used for each different
   608  //         value of n. This initialization does not have to be
   609  //         repeated so long as n remains unchanged thus subsequent
   610  //         transforms can be obtained faster than the first.
   611  //         The same work array can be used by Rfftf and Rfftb.
   612  //
   613  //  ifac   A work array containing the factors of n. ifac must have
   614  //         length of at least 15.
   615  //
   616  //  output parameters
   617  //
   618  //  r      for n even and for i = 0, ..., n
   619  //           r[i] = r[0]+(-1)^i*r[n-1]
   620  //             plus the sum from k=1 to k=n/2-1 of
   621  //               2*r(2*k-1)*cos(k*i*2*pi/n)
   622  //               -2*r(2*k)*sin(k*i*2*pi/n)
   623  //
   624  //         for n odd and for i = 0, ..., n-1
   625  //           r[i] = r[0] plus the sum from k=1 to k=(n-1)/2 of
   626  //             2*r(2*k-1)*cos(k*i*2*pi/n)
   627  //             -2*r(2*k)*sin(k*i*2*pi/n)
   628  //
   629  //  This transform is unnormalized since a call of Rfftf
   630  //  followed by a call of Rfftb will multiply the input
   631  //  sequence by n.
   632  //
   633  //  work   Contains results which must not be destroyed between
   634  //         calls of Rfftf or Rfftb.
   635  //  ifac   Contains results which must not be destroyed between
   636  //         calls of Rfftf or Rfftb.
   637  func Rfftb(n int, r, work []float64, ifac []int) {
   638  	if len(r) < n {
   639  		panic("fourier: short sequence")
   640  	}
   641  	if len(work) < 2*n {
   642  		panic("fourier: short work")
   643  	}
   644  	if len(ifac) < 15 {
   645  		panic("fourier: short ifac")
   646  	}
   647  	if n == 1 {
   648  		return
   649  	}
   650  	rfftb1(n, r[:n], work[:n], work[n:2*n], ifac[:15])
   651  }
   652  
   653  func rfftb1(n int, c, ch, wa []float64, ifac []int) {
   654  	nf := ifac[1]
   655  	na := false
   656  	l1 := 1
   657  	iw := 0
   658  
   659  	for k1 := 1; k1 <= nf; k1++ {
   660  		ip := ifac[k1+1]
   661  		l2 := ip * l1
   662  		ido := n / l2
   663  		idl1 := ido * l1
   664  
   665  		switch ip {
   666  		case 4:
   667  			ix2 := iw + ido
   668  			ix3 := ix2 + ido
   669  			if na {
   670  				radb4(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:])
   671  			} else {
   672  				radb4(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:])
   673  			}
   674  			na = !na
   675  		case 2:
   676  			if na {
   677  				radb2(ido, l1, ch, c, wa[iw:])
   678  			} else {
   679  				radb2(ido, l1, c, ch, wa[iw:])
   680  			}
   681  			na = !na
   682  		case 3:
   683  			ix2 := iw + ido
   684  			if na {
   685  				radb3(ido, l1, ch, c, wa[iw:], wa[ix2:])
   686  			} else {
   687  				radb3(ido, l1, c, ch, wa[iw:], wa[ix2:])
   688  			}
   689  			na = !na
   690  		case 5:
   691  			ix2 := iw + ido
   692  			ix3 := ix2 + ido
   693  			ix4 := ix3 + ido
   694  			if na {
   695  				radb5(ido, l1, ch, c, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:])
   696  			} else {
   697  				radb5(ido, l1, c, ch, wa[iw:], wa[ix2:], wa[ix3:], wa[ix4:])
   698  			}
   699  			na = !na
   700  		default:
   701  			if na {
   702  				radbg(ido, ip, l1, idl1, ch, ch, ch, c, c, wa[iw:])
   703  			} else {
   704  				radbg(ido, ip, l1, idl1, c, c, c, ch, ch, wa[iw:])
   705  			}
   706  			if ido == 1 {
   707  				na = !na
   708  			}
   709  		}
   710  
   711  		l1 = l2
   712  		iw += (ip - 1) * ido
   713  	}
   714  
   715  	if na {
   716  		for i := 0; i < n; i++ {
   717  			c[i] = ch[i]
   718  		}
   719  	}
   720  }
   721  
   722  func radb2(ido, l1 int, cc, ch, wa1 []float64) {
   723  	cc3 := newThreeArray(ido, 2, l1, cc)
   724  	ch3 := newThreeArray(ido, l1, 2, ch)
   725  
   726  	for k := 0; k < l1; k++ {
   727  		ch3.set(0, k, 0, cc3.at(0, 0, k)+cc3.at(ido-1, 1, k))
   728  		ch3.set(0, k, 1, cc3.at(0, 0, k)-cc3.at(ido-1, 1, k))
   729  	}
   730  
   731  	if ido < 2 {
   732  		return
   733  	}
   734  	if ido > 2 {
   735  		idp2 := ido + 1
   736  		for k := 0; k < l1; k++ {
   737  			for i := 2; i < ido; i += 2 {
   738  				ic := idp2 - (i + 1)
   739  
   740  				ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+cmplx.Conj(cc3.atCmplx(ic-1, 1, k)))
   741  
   742  				t2 := cc3.atCmplx(i-1, 0, k) - cmplx.Conj(cc3.atCmplx(ic-1, 1, k))
   743  				ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*t2)
   744  			}
   745  		}
   746  
   747  		if ido%2 == 1 {
   748  			return
   749  		}
   750  	}
   751  	for k := 0; k < l1; k++ {
   752  		ch3.set(ido-1, k, 0, 2*cc3.at(ido-1, 0, k))
   753  		ch3.set(ido-1, k, 1, -2*cc3.at(0, 1, k))
   754  	}
   755  }
   756  
   757  func radb3(ido, l1 int, cc, ch, wa1, wa2 []float64) {
   758  	const (
   759  		taur = -0.5
   760  		taui = 0.866025403784439 // sqrt(3)/2
   761  	)
   762  
   763  	cc3 := newThreeArray(ido, 3, l1, cc)
   764  	ch3 := newThreeArray(ido, l1, 3, ch)
   765  
   766  	for k := 0; k < l1; k++ {
   767  		tr2 := cc3.at(ido-1, 1, k) + cc3.at(ido-1, 1, k)
   768  		cr2 := cc3.at(0, 0, k) + taur*tr2
   769  		ch3.set(0, k, 0, cc3.at(0, 0, k)+tr2)
   770  		ci3 := taui * (cc3.at(0, 2, k) + cc3.at(0, 2, k))
   771  		ch3.set(0, k, 1, cr2-ci3)
   772  		ch3.set(0, k, 2, cr2+ci3)
   773  	}
   774  
   775  	if ido == 1 {
   776  		return
   777  	}
   778  
   779  	idp2 := ido + 1
   780  	for k := 0; k < l1; k++ {
   781  		for i := 2; i < ido; i += 2 {
   782  			ic := idp2 - (i + 1)
   783  
   784  			t2 := cc3.atCmplx(i-1, 2, k) + cmplx.Conj(cc3.atCmplx(ic-1, 1, k))
   785  			c2 := cc3.atCmplx(i-1, 0, k) + scale(taur, t2)
   786  			ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+t2)
   787  
   788  			c3 := scale(taui, cc3.atCmplx(i-1, 2, k)-cmplx.Conj(cc3.atCmplx(ic-1, 1, k)))
   789  			d2 := c2 - cmplx.Conj(swap(c3))
   790  			d3 := c2 + cmplx.Conj(swap(c3))
   791  			ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*d2)
   792  			ch3.setCmplx(i-1, k, 2, complex(wa2[i-2], wa2[i-1])*d3)
   793  		}
   794  	}
   795  }
   796  
   797  func radb4(ido, l1 int, cc, ch, wa1, wa2, wa3 []float64) {
   798  	cc3 := newThreeArray(ido, 4, l1, cc)
   799  	ch3 := newThreeArray(ido, l1, 4, ch)
   800  
   801  	for k := 0; k < l1; k++ {
   802  		tr1 := cc3.at(0, 0, k) - cc3.at(ido-1, 3, k)
   803  		tr2 := cc3.at(0, 0, k) + cc3.at(ido-1, 3, k)
   804  		tr3 := cc3.at(ido-1, 1, k) + cc3.at(ido-1, 1, k)
   805  		tr4 := cc3.at(0, 2, k) + cc3.at(0, 2, k)
   806  		ch3.set(0, k, 0, tr2+tr3)
   807  		ch3.set(0, k, 1, tr1-tr4)
   808  		ch3.set(0, k, 2, tr2-tr3)
   809  		ch3.set(0, k, 3, tr1+tr4)
   810  	}
   811  
   812  	if ido < 2 {
   813  		return
   814  	}
   815  	if ido > 2 {
   816  		idp2 := ido + 1
   817  		for k := 0; k < l1; k++ {
   818  			for i := 2; i < ido; i += 2 {
   819  				ic := idp2 - (i + 1)
   820  
   821  				t1 := cc3.atCmplx(i-1, 0, k) - cmplx.Conj(cc3.atCmplx(ic-1, 3, k))
   822  				t2 := cc3.atCmplx(i-1, 0, k) + cmplx.Conj(cc3.atCmplx(ic-1, 3, k))
   823  				t3 := cc3.atCmplx(i-1, 2, k) + cmplx.Conj(cc3.atCmplx(ic-1, 1, k))
   824  				t4 := swap(cc3.atCmplx(i-1, 2, k) - cmplx.Conj(cc3.atCmplx(ic-1, 1, k)))
   825  				ch3.setCmplx(i-1, k, 0, t2+t3)
   826  
   827  				c2 := t1 - cmplx.Conj(t4)
   828  				c3 := t2 - t3
   829  				c4 := t1 + cmplx.Conj(t4)
   830  				ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*c2)
   831  				ch3.setCmplx(i-1, k, 2, complex(wa2[i-2], wa2[i-1])*c3)
   832  				ch3.setCmplx(i-1, k, 3, complex(wa3[i-2], wa3[i-1])*c4)
   833  			}
   834  		}
   835  
   836  		if ido%2 == 1 {
   837  			return
   838  		}
   839  	}
   840  	for k := 0; k < l1; k++ {
   841  		tr1 := cc3.at(ido-1, 0, k) - cc3.at(ido-1, 2, k)
   842  		ti1 := cc3.at(0, 1, k) + cc3.at(0, 3, k)
   843  		tr2 := cc3.at(ido-1, 0, k) + cc3.at(ido-1, 2, k)
   844  		ti2 := cc3.at(0, 3, k) - cc3.at(0, 1, k)
   845  		ch3.set(ido-1, k, 0, tr2+tr2)
   846  		ch3.set(ido-1, k, 1, math.Sqrt2*(tr1-ti1))
   847  		ch3.set(ido-1, k, 2, ti2+ti2)
   848  		ch3.set(ido-1, k, 3, -math.Sqrt2*(tr1+ti1))
   849  	}
   850  }
   851  
   852  func radb5(ido, l1 int, cc, ch, wa1, wa2, wa3, wa4 []float64) {
   853  	const (
   854  		tr11 = 0.309016994374947
   855  		ti11 = 0.951056516295154
   856  		tr12 = -0.809016994374947
   857  		ti12 = 0.587785252292473
   858  	)
   859  
   860  	cc3 := newThreeArray(ido, 5, l1, cc)
   861  	ch3 := newThreeArray(ido, l1, 5, ch)
   862  
   863  	for k := 0; k < l1; k++ {
   864  		tr2 := cc3.at(ido-1, 1, k) + cc3.at(ido-1, 1, k)
   865  		tr3 := cc3.at(ido-1, 3, k) + cc3.at(ido-1, 3, k)
   866  		ti4 := cc3.at(0, 4, k) + cc3.at(0, 4, k)
   867  		ti5 := cc3.at(0, 2, k) + cc3.at(0, 2, k)
   868  		ch3.set(0, k, 0, cc3.at(0, 0, k)+tr2+tr3)
   869  
   870  		cr2 := cc3.at(0, 0, k) + tr11*tr2 + tr12*tr3
   871  
   872  		cr3 := cc3.at(0, 0, k) + tr12*tr2 + tr11*tr3
   873  
   874  		ci4 := ti12*ti5 - ti11*ti4
   875  
   876  		ci5 := ti11*ti5 + ti12*ti4
   877  
   878  		ch3.set(0, k, 1, cr2-ci5)
   879  		ch3.set(0, k, 2, cr3-ci4)
   880  		ch3.set(0, k, 3, cr3+ci4)
   881  		ch3.set(0, k, 4, cr2+ci5)
   882  	}
   883  
   884  	if ido == 1 {
   885  		return
   886  	}
   887  
   888  	idp2 := ido + 1
   889  	for k := 0; k < l1; k++ {
   890  		for i := 2; i < ido; i += 2 {
   891  			ic := idp2 - (i + 1)
   892  
   893  			t2 := cc3.atCmplx(i-1, 2, k) + cmplx.Conj(cc3.atCmplx(ic-1, 1, k))
   894  			t3 := cc3.atCmplx(i-1, 4, k) + cmplx.Conj(cc3.atCmplx(ic-1, 3, k))
   895  			t4 := cc3.atCmplx(i-1, 4, k) - cmplx.Conj(cc3.atCmplx(ic-1, 3, k))
   896  			t5 := cc3.atCmplx(i-1, 2, k) - cmplx.Conj(cc3.atCmplx(ic-1, 1, k))
   897  			ch3.setCmplx(i-1, k, 0, cc3.atCmplx(i-1, 0, k)+t2+t3)
   898  
   899  			c2 := cc3.atCmplx(i-1, 0, k) + scale(tr11, t2) + scale(tr12, t3)
   900  			c3 := cc3.atCmplx(i-1, 0, k) + scale(tr12, t2) + scale(tr11, t3)
   901  			c4 := scale(ti12, t5) - scale(ti11, t4)
   902  			c5 := scale(ti11, t5) + scale(ti12, t4)
   903  			d2 := c2 - cmplx.Conj(swap(c5))
   904  			d3 := c3 - cmplx.Conj(swap(c4))
   905  			d4 := c3 + cmplx.Conj(swap(c4))
   906  			d5 := c2 + cmplx.Conj(swap(c5))
   907  			ch3.setCmplx(i-1, k, 1, complex(wa1[i-2], wa1[i-1])*d2)
   908  			ch3.setCmplx(i-1, k, 2, complex(wa2[i-2], wa2[i-1])*d3)
   909  			ch3.setCmplx(i-1, k, 3, complex(wa3[i-2], wa3[i-1])*d4)
   910  			ch3.setCmplx(i-1, k, 4, complex(wa4[i-2], wa4[i-1])*d5)
   911  		}
   912  	}
   913  }
   914  
   915  func radbg(ido, ip, l1, idl1 int, cc, c1, c2, ch, ch2, wa []float64) {
   916  	cc3 := newThreeArray(ido, ip, l1, cc)
   917  	c13 := newThreeArray(ido, l1, ip, c1)
   918  	ch3 := newThreeArray(ido, l1, ip, ch)
   919  	c2m := newTwoArray(idl1, ip, c2)
   920  	ch2m := newTwoArray(idl1, ip, ch2)
   921  
   922  	arg := 2 * math.Pi / float64(ip)
   923  	dcp := math.Cos(arg)
   924  	dsp := math.Sin(arg)
   925  	ipph := (ip + 1) / 2
   926  	nbd := (ido - 1) / 2
   927  
   928  	if ido < l1 {
   929  		for i := 0; i < ido; i++ {
   930  			for k := 0; k < l1; k++ {
   931  				ch3.set(i, k, 0, cc3.at(i, 0, k))
   932  			}
   933  		}
   934  	} else {
   935  		for k := 0; k < l1; k++ {
   936  			for i := 0; i < ido; i++ {
   937  				ch3.set(i, k, 0, cc3.at(i, 0, k))
   938  			}
   939  		}
   940  	}
   941  
   942  	for j := 1; j < ipph; j++ {
   943  		jc := ip - j
   944  		j2 := 2 * j
   945  		for k := 0; k < l1; k++ {
   946  			ch3.set(0, k, j, cc3.at(ido-1, j2-1, k)+cc3.at(ido-1, j2-1, k))
   947  			ch3.set(0, k, jc, cc3.at(0, j2, k)+cc3.at(0, j2, k))
   948  		}
   949  	}
   950  
   951  	if ido != 1 {
   952  		if nbd < l1 {
   953  			for j := 1; j < ipph; j++ {
   954  				jc := ip - j
   955  				j2 := 2 * j
   956  				for i := 2; i < ido; i += 2 {
   957  					ic := ido - i
   958  					for k := 0; k < l1; k++ {
   959  						ch3.setCmplx(i-1, k, j, cc3.atCmplx(i-1, j2, k)+cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k)))
   960  						ch3.setCmplx(i-1, k, jc, cc3.atCmplx(i-1, j2, k)-cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k)))
   961  					}
   962  				}
   963  			}
   964  		} else {
   965  			for j := 1; j < ipph; j++ {
   966  				jc := ip - j
   967  				j2 := 2 * j
   968  				for k := 0; k < l1; k++ {
   969  					for i := 2; i < ido; i += 2 {
   970  						ic := ido - i
   971  						ch3.setCmplx(i-1, k, j, cc3.atCmplx(i-1, j2, k)+cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k)))
   972  						ch3.setCmplx(i-1, k, jc, cc3.atCmplx(i-1, j2, k)-cmplx.Conj(cc3.atCmplx(ic-1, j2-1, k)))
   973  					}
   974  				}
   975  			}
   976  		}
   977  	}
   978  
   979  	ar1 := 1.0
   980  	ai1 := 0.0
   981  	for l := 1; l < ipph; l++ {
   982  		lc := ip - l
   983  		ar1h := dcp*ar1 - dsp*ai1
   984  		ai1 = dcp*ai1 + dsp*ar1
   985  		ar1 = ar1h
   986  		for ik := 0; ik < idl1; ik++ {
   987  			c2m.set(ik, l, ch2m.at(ik, 0)+ar1*ch2m.at(ik, 1))
   988  			c2m.set(ik, lc, ai1*ch2m.at(ik, ip-1))
   989  		}
   990  		dc2 := ar1
   991  		ds2 := ai1
   992  		ar2 := ar1
   993  		ai2 := ai1
   994  		for j := 2; j < ipph; j++ {
   995  			jc := ip - j
   996  			ar2h := dc2*ar2 - ds2*ai2
   997  			ai2 = dc2*ai2 + ds2*ar2
   998  			ar2 = ar2h
   999  			for ik := 0; ik < idl1; ik++ {
  1000  				c2m.add(ik, l, ar2*ch2m.at(ik, j))
  1001  				c2m.add(ik, lc, ai2*ch2m.at(ik, jc))
  1002  			}
  1003  		}
  1004  	}
  1005  
  1006  	for j := 1; j < ipph; j++ {
  1007  		for ik := 0; ik < idl1; ik++ {
  1008  			ch2m.add(ik, 0, ch2m.at(ik, j))
  1009  		}
  1010  	}
  1011  	for j := 1; j < ipph; j++ {
  1012  		jc := ip - j
  1013  		for k := 0; k < l1; k++ {
  1014  			ch3.set(0, k, j, c13.at(0, k, j)-c13.at(0, k, jc))
  1015  			ch3.set(0, k, jc, c13.at(0, k, j)+c13.at(0, k, jc))
  1016  		}
  1017  	}
  1018  
  1019  	if ido != 1 {
  1020  		if nbd < l1 {
  1021  			for j := 1; j < ipph; j++ {
  1022  				jc := ip - j
  1023  				for i := 2; i < ido; i += 2 {
  1024  					for k := 0; k < l1; k++ {
  1025  						ch3.setCmplx(i-1, k, j, c13.atCmplx(i-1, k, j)-cmplx.Conj(swap(c13.atCmplx(i-1, k, jc))))
  1026  						ch3.setCmplx(i-1, k, jc, c13.atCmplx(i-1, k, j)+cmplx.Conj(swap(c13.atCmplx(i-1, k, jc))))
  1027  					}
  1028  				}
  1029  			}
  1030  		} else {
  1031  			for j := 1; j < ipph; j++ {
  1032  				jc := ip - j
  1033  				for k := 0; k < l1; k++ {
  1034  					for i := 2; i < ido; i += 2 {
  1035  						ch3.setCmplx(i-1, k, j, c13.atCmplx(i-1, k, j)-cmplx.Conj(swap(c13.atCmplx(i-1, k, jc))))
  1036  						ch3.setCmplx(i-1, k, jc, c13.atCmplx(i-1, k, j)+cmplx.Conj(swap(c13.atCmplx(i-1, k, jc))))
  1037  					}
  1038  				}
  1039  			}
  1040  		}
  1041  	}
  1042  
  1043  	if ido == 1 {
  1044  		return
  1045  	}
  1046  	for ik := 0; ik < idl1; ik++ {
  1047  		c2m.set(ik, 0, ch2m.at(ik, 0))
  1048  	}
  1049  	for j := 1; j < ip; j++ {
  1050  		for k := 0; k < l1; k++ {
  1051  			c13.set(0, k, j, ch3.at(0, k, j))
  1052  		}
  1053  	}
  1054  
  1055  	is := -ido - 1
  1056  	if nbd > l1 {
  1057  		for j := 1; j < ip; j++ {
  1058  			is += ido
  1059  			for k := 0; k < l1; k++ {
  1060  				idij := is
  1061  				for i := 2; i < ido; i += 2 {
  1062  					idij += 2
  1063  					c13.setCmplx(i-1, k, j, complex(wa[idij-1], wa[idij])*ch3.atCmplx(i-1, k, j))
  1064  				}
  1065  			}
  1066  		}
  1067  		return
  1068  	}
  1069  	for j := 1; j < ip; j++ {
  1070  		is += ido
  1071  		idij := is
  1072  		for i := 2; i < ido; i += 2 {
  1073  			idij += 2
  1074  			for k := 0; k < l1; k++ {
  1075  				c13.setCmplx(i-1, k, j, complex(wa[idij-1], wa[idij])*ch3.atCmplx(i-1, k, j))
  1076  			}
  1077  		}
  1078  	}
  1079  }