gonum.org/v1/gonum@v0.14.0/dsp/fourier/internal/fftpack/cosq.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 cosq 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 "math"
    12  
    13  // Cosqi initializes the array work which is used in both Cosqf
    14  // and Cosqb. The prime factorization of n together with a
    15  // tabulation of the trigonometric functions are computed and
    16  // stored in work.
    17  //
    18  //	Input parameter:
    19  //
    20  //	n       The length of the sequence to be transformed. the method
    21  //	        is most efficient when n+1 is a product of small primes.
    22  //
    23  //	Output parameters:
    24  //
    25  //	work    A work array which must be dimensioned at least 3*n.
    26  //	        The same work array can be used for both Cosqf and Cosqb
    27  //	        as long as n remains unchanged. Different work arrays
    28  //	        are required for different values of n. The contents of
    29  //	        work must not be changed between calls of Cosqf or Cosqb.
    30  //
    31  //	ifac    An integer work array of length at least 15.
    32  func Cosqi(n int, work []float64, ifac []int) {
    33  	if len(work) < 3*n {
    34  		panic("fourier: short work")
    35  	}
    36  	if len(ifac) < 15 {
    37  		panic("fourier: short ifac")
    38  	}
    39  	dt := 0.5 * math.Pi / float64(n)
    40  	for k := range work[:n] {
    41  		work[k] = math.Cos(float64(k+1) * dt)
    42  	}
    43  	Rffti(n, work[n:], ifac)
    44  }
    45  
    46  // Cosqf computes the Fast Fourier Transform of quarter wave data.
    47  // That is, Cosqf computes the coefficients in a cosine series
    48  // representation with only odd wave numbers. The transform is
    49  // defined below at output parameter x.
    50  //
    51  // Cosqb is the unnormalized inverse of Cosqf since a call of Cosqf
    52  // followed by a call of Cosqb will multiply the input sequence x
    53  // by 4*n.
    54  //
    55  // The array work which is used by subroutine Cosqf must be
    56  // initialized by calling subroutine Cosqi(n,work).
    57  //
    58  //	Input parameters:
    59  //
    60  //	n       The length of the array x to be transformed. The method
    61  //	        is most efficient when n is a product of small primes.
    62  //
    63  //	x       An array which contains the sequence to be transformed.
    64  //
    65  //	work    A work array which must be dimensioned at least 3*n
    66  //	        in the program that calls Cosqf. The work array must be
    67  //	        initialized by calling subroutine Cosqi(n,work) and a
    68  //	        different work array must be used for each different
    69  //	        value of n. This initialization does not have to be
    70  //	        repeated so long as n remains unchanged thus subsequent
    71  //	        transforms can be obtained faster than the first.
    72  //
    73  //	ifac    An integer work array of length at least 15.
    74  //
    75  //	Output parameters:
    76  //
    77  //	x       for i=0, ..., n-1
    78  //	          x[i] = x[i] + the sum from k=0 to k=n-2 of
    79  //	              2*x[k]*cos((2*i+1)*k*pi/(2*n))
    80  //
    81  //	        A call of Cosqf followed by a call of
    82  //	        Cosqb will multiply the sequence x by 4*n.
    83  //	        Therefore Cosqb is the unnormalized inverse
    84  //	        of Cosqf.
    85  //
    86  //	work    Contains initialization calculations which must not
    87  //	        be destroyed between calls of Cosqf or Cosqb.
    88  func Cosqf(n int, x, work []float64, ifac []int) {
    89  	if len(x) < n {
    90  		panic("fourier: short sequence")
    91  	}
    92  	if len(work) < 3*n {
    93  		panic("fourier: short work")
    94  	}
    95  	if len(ifac) < 15 {
    96  		panic("fourier: short ifac")
    97  	}
    98  	if n < 2 {
    99  		return
   100  	}
   101  	if n == 2 {
   102  		tsqx := math.Sqrt2 * x[1]
   103  		x[1] = x[0] - tsqx
   104  		x[0] += tsqx
   105  		return
   106  	}
   107  	cosqf1(n, x, work, work[n:], ifac)
   108  }
   109  
   110  func cosqf1(n int, x, w, xh []float64, ifac []int) {
   111  	for k := 1; k < (n+1)/2; k++ {
   112  		kc := n - k
   113  		xh[k] = x[k] + x[kc]
   114  		xh[kc] = x[k] - x[kc]
   115  	}
   116  	if n%2 == 0 {
   117  		xh[(n+1)/2] = 2 * x[(n+1)/2]
   118  	}
   119  	for k := 1; k < (n+1)/2; k++ {
   120  		kc := n - k
   121  		x[k] = w[k-1]*xh[kc] + w[kc-1]*xh[k]
   122  		x[kc] = w[k-1]*xh[k] - w[kc-1]*xh[kc]
   123  	}
   124  	if n%2 == 0 {
   125  		x[(n+1)/2] = w[(n-1)/2] * xh[(n+1)/2]
   126  	}
   127  	Rfftf(n, x, xh, ifac)
   128  	for i := 2; i < n; i += 2 {
   129  		x[i-1], x[i] = x[i-1]-x[i], x[i-1]+x[i]
   130  	}
   131  }
   132  
   133  // Cosqb computes the Fast Fourier Transform of quarter wave data.
   134  // That is, Cosqb computes a sequence from its representation in
   135  // terms of a cosine series with odd wave numbers. The transform
   136  // is defined below at output parameter x.
   137  //
   138  // Cosqf is the unnormalized inverse of Cosqb since a call of Cosqb
   139  // followed by a call of Cosqf will multiply the input sequence x
   140  // by 4*n.
   141  //
   142  // The array work which is used by subroutine Cosqb must be
   143  // initialized by calling subroutine Cosqi(n,work).
   144  //
   145  //	Input parameters:
   146  //
   147  //	n       The length of the array x to be transformed. The method
   148  //	        is most efficient when n is a product of small primes.
   149  //
   150  //	x       An array which contains the sequence to be transformed.
   151  //
   152  //	work    A work array which must be dimensioned at least 3*n
   153  //	        in the program that calls Cosqb. The work array must be
   154  //	        initialized by calling subroutine Cosqi(n,work) and a
   155  //	        different work array must be used for each different
   156  //	        value of n. This initialization does not have to be
   157  //	        repeated so long as n remains unchanged thus subsequent
   158  //	        transforms can be obtained faster than the first.
   159  //
   160  //	ifac    An integer work array of length at least 15.
   161  //
   162  //	Output parameters:
   163  //
   164  //	x       for i=0, ..., n-1
   165  //	          x[i]= the sum from k=0 to k=n-1 of
   166  //	            4*x[k]*cos((2*k+1)*i*pi/(2*n))
   167  //
   168  //	        A call of Cosqb followed by a call of
   169  //	        Cosqf will multiply the sequence x by 4*n.
   170  //	        Therefore Cosqf is the unnormalized inverse
   171  //	        of Cosqb.
   172  //
   173  //	work    Contains initialization calculations which must not
   174  //	        be destroyed between calls of Cosqb or Cosqf.
   175  func Cosqb(n int, x, work []float64, ifac []int) {
   176  	if len(x) < n {
   177  		panic("fourier: short sequence")
   178  	}
   179  	if len(work) < 3*n {
   180  		panic("fourier: short work")
   181  	}
   182  	if len(ifac) < 15 {
   183  		panic("fourier: short ifac")
   184  	}
   185  
   186  	if n < 2 {
   187  		x[0] *= 4
   188  		return
   189  	}
   190  	if n == 2 {
   191  		x[0], x[1] = 4*(x[0]+x[1]), 2*math.Sqrt2*(x[0]-x[1])
   192  		return
   193  	}
   194  	cosqb1(n, x, work, work[n:], ifac)
   195  }
   196  
   197  func cosqb1(n int, x, w, xh []float64, ifac []int) {
   198  	for i := 2; i < n; i += 2 {
   199  		x[i-1], x[i] = x[i-1]+x[i], x[i]-x[i-1]
   200  	}
   201  	x[0] *= 2
   202  	if n%2 == 0 {
   203  		x[n-1] *= 2
   204  	}
   205  	Rfftb(n, x, xh, ifac)
   206  	for k := 1; k < (n+1)/2; k++ {
   207  		kc := n - k
   208  		xh[k] = w[k-1]*x[kc] + w[kc-1]*x[k]
   209  		xh[kc] = w[k-1]*x[k] - w[kc-1]*x[kc]
   210  	}
   211  	if n%2 == 0 {
   212  		x[(n+1)/2] *= 2 * w[(n-1)/2]
   213  	}
   214  	for k := 1; k < (n+1)/2; k++ {
   215  		x[k] = xh[k] + xh[n-k]
   216  		x[n-k] = xh[k] - xh[n-k]
   217  	}
   218  	x[0] *= 2
   219  }