github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/dsp/fourier/radix24.go (about)

     1  // Copyright ©2020 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  package fourier
     6  
     7  import (
     8  	"math"
     9  	"math/bits"
    10  	"math/cmplx"
    11  )
    12  
    13  // CoefficientsRadix2 computes the Fourier coefficients of the input
    14  // sequence, converting the time series in seq into the frequency spectrum,
    15  // in place and returning it. This transform is unnormalized; a call to
    16  // CoefficientsRadix2 followed by a call of SequenceRadix2 will multiply the
    17  // input sequence by the length of the sequence.
    18  //
    19  // CoefficientsRadix2 does not allocate, requiring that FFT twiddle factors
    20  // be calculated lazily. For performance reasons, this is done by successive
    21  // multiplication, so numerical accuracies can accumulate for large inputs.
    22  // If accuracy is needed, the FFT or CmplxFFT types should be used.
    23  //
    24  // If the length of seq is not an integer power of 2, CoefficientsRadix2 will
    25  // panic.
    26  func CoefficientsRadix2(seq []complex128) []complex128 {
    27  	x := seq
    28  	switch len(x) {
    29  	default:
    30  		if bits.OnesCount(uint(len(x))) != 1 {
    31  			panic("fourier: radix-2 fft called with non-power 2 length")
    32  		}
    33  
    34  	case 0, 1:
    35  		return x
    36  
    37  	case 2:
    38  		x[0], x[1] =
    39  			x[0]+x[1],
    40  			x[0]-x[1]
    41  		return x
    42  
    43  	case 4:
    44  		t := x[1] + x[3]
    45  		u := x[2]
    46  		v := negi(x[1] - x[3])
    47  		x[0], x[1], x[2], x[3] =
    48  			x[0]+u+t,
    49  			x[0]-u+v,
    50  			x[0]+u-t,
    51  			x[0]-u-v
    52  		return x
    53  	}
    54  
    55  	bitReversePermute(x)
    56  
    57  	for k := 0; k < len(x); k += 4 {
    58  		t := x[k+2] + x[k+3]
    59  		u := x[k+1]
    60  		v := negi(x[k+2] - x[k+3])
    61  		x[k], x[k+1], x[k+2], x[k+3] =
    62  			x[k]+u+t,
    63  			x[k]-u+v,
    64  			x[k]+u-t,
    65  			x[k]-u-v
    66  	}
    67  
    68  	for m := 4; m < len(x); m *= 2 {
    69  		f := swap(complex(math.Sincos(-math.Pi / float64(m))))
    70  		for k := 0; k < len(x); k += 2 * m {
    71  			w := 1 + 0i
    72  			for j := 0; j < m; j++ {
    73  				i := j + k
    74  
    75  				u := w * x[i+m]
    76  				x[i], x[i+m] =
    77  					x[i]+u,
    78  					x[i]-u
    79  
    80  				w *= f
    81  			}
    82  		}
    83  	}
    84  
    85  	return x
    86  }
    87  
    88  // bitReversePermute performs a bit-reversal permutation on x.
    89  func bitReversePermute(x []complex128) {
    90  	if len(x) < 2 || bits.OnesCount(uint(len(x))) != 1 {
    91  		panic("fourier: invalid bitReversePermute call")
    92  	}
    93  	lz := bits.LeadingZeros(uint(len(x) - 1))
    94  	i := 0
    95  	for ; i < len(x)/2; i++ {
    96  		j := int(bits.Reverse(uint(i)) >> lz)
    97  		if i < j {
    98  			x[i], x[j] = x[j], x[i]
    99  		}
   100  	}
   101  	for i++; i < len(x); i += 2 {
   102  		j := int(bits.Reverse(uint(i)) >> lz)
   103  		if i < j {
   104  			x[i], x[j] = x[j], x[i]
   105  		}
   106  	}
   107  }
   108  
   109  // SequenceRadix2 computes the real periodic sequence from the Fourier
   110  // coefficients, converting the frequency spectrum in coeff into a time
   111  // series, in place and returning it. This transform is unnormalized; a
   112  // call to CoefficientsRadix2 followed by a call of SequenceRadix2 will
   113  // multiply the input sequence by the length of the sequence.
   114  //
   115  // SequenceRadix2 does not allocate, requiring that FFT twiddle factors
   116  // be calculated lazily. For performance reasons, this is done by successive
   117  // multiplication, so numerical accuracies can accumulate for large inputs.
   118  // If accuracy is needed, the FFT or CmplxFFT types should be used.
   119  //
   120  // If the length of coeff is not an integer power of 2, SequenceRadix2
   121  // will panic.
   122  func SequenceRadix2(coeff []complex128) []complex128 {
   123  	x := coeff
   124  	for i, j := 1, len(x)-1; i < j; i, j = i+1, j-1 {
   125  		x[i], x[j] = x[j], x[i]
   126  	}
   127  
   128  	CoefficientsRadix2(x)
   129  	return x
   130  }
   131  
   132  // PadRadix2 returns the values in x in a slice that is an integer
   133  // power of 2 long. If x already has an integer power of 2 length
   134  // it is returned unaltered.
   135  func PadRadix2(x []complex128) []complex128 {
   136  	if len(x) == 0 {
   137  		return x
   138  	}
   139  	b := bits.Len(uint(len(x)))
   140  	if len(x) == 1<<(b-1) {
   141  		return x
   142  	}
   143  	p := make([]complex128, 1<<b)
   144  	copy(p, x)
   145  	return p
   146  }
   147  
   148  // TrimRadix2 returns the largest slice of x that is has an integer
   149  // power of 2 length, and a slice holding the remaining elements.
   150  func TrimRadix2(x []complex128) (even, remains []complex128) {
   151  	if len(x) == 0 {
   152  		return x, nil
   153  	}
   154  	n := 1 << (bits.Len(uint(len(x))) - 1)
   155  	return x[:n], x[n:]
   156  }
   157  
   158  // CoefficientsRadix4 computes the Fourier coefficients of the input
   159  // sequence, converting the time series in seq into the frequency spectrum,
   160  // in place and returning it. This transform is unnormalized; a call to
   161  // CoefficientsRadix4 followed by a call of SequenceRadix4 will multiply the
   162  // input sequence by the length of the sequence.
   163  //
   164  // CoefficientsRadix4 does not allocate, requiring that FFT twiddle factors
   165  // be calculated lazily. For performance reasons, this is done by successive
   166  // multiplication, so numerical accuracies can accumulate for large inputs.
   167  // If accuracy is needed, the FFT or CmplxFFT types should be used.
   168  //
   169  // If the length of seq is not an integer power of 4, CoefficientsRadix4 will
   170  // panic.
   171  func CoefficientsRadix4(seq []complex128) []complex128 {
   172  	x := seq
   173  	switch len(x) {
   174  	default:
   175  		if bits.OnesCount(uint(len(x))) != 1 || bits.TrailingZeros(uint(len(x)))&0x1 != 0 {
   176  			panic("fourier: radix-4 fft called with non-power 4 length")
   177  		}
   178  
   179  	case 0, 1:
   180  		return x
   181  
   182  	case 4:
   183  		t := x[1] + x[3]
   184  		u := x[2]
   185  		v := negi(x[1] - x[3])
   186  		x[0], x[1], x[2], x[3] =
   187  			x[0]+u+t,
   188  			x[0]-u+v,
   189  			x[0]+u-t,
   190  			x[0]-u-v
   191  		return x
   192  	}
   193  
   194  	bitPairReversePermute(x)
   195  
   196  	for k := 0; k < len(x); k += 4 {
   197  		t := x[k+1] + x[k+3]
   198  		u := x[k+2]
   199  		v := negi(x[k+1] - x[k+3])
   200  		x[k], x[k+1], x[k+2], x[k+3] =
   201  			x[k]+u+t,
   202  			x[k]-u+v,
   203  			x[k]+u-t,
   204  			x[k]-u-v
   205  	}
   206  
   207  	for m := 4; m < len(x); m *= 4 {
   208  		f := swap(complex(math.Sincos((-math.Pi / 2) / float64(m))))
   209  		for k := 0; k < len(x); k += m * 4 {
   210  			w := 1 + 0i
   211  			w2 := w
   212  			w3 := w2
   213  			for j := 0; j < m; j++ {
   214  				i := j + k
   215  
   216  				t := x[i+m]*w + x[i+3*m]*w3
   217  				u := x[i+2*m] * w2
   218  				v := negi(x[i+m]*w - x[i+3*m]*w3)
   219  				x[i], x[i+m], x[i+2*m], x[i+3*m] =
   220  					x[i]+u+t,
   221  					x[i]-u+v,
   222  					x[i]+u-t,
   223  					x[i]-u-v
   224  
   225  				wt := f
   226  				w *= wt
   227  				wt *= f
   228  				w2 *= wt
   229  				wt *= f
   230  				w3 *= wt
   231  			}
   232  		}
   233  	}
   234  
   235  	return x
   236  }
   237  
   238  // bitPairReversePermute performs a bit pair-reversal permutation on x.
   239  func bitPairReversePermute(x []complex128) {
   240  	if len(x) < 4 || bits.OnesCount(uint(len(x))) != 1 || bits.TrailingZeros(uint(len(x)))&0x1 != 0 {
   241  		panic("fourier: invalid bitPairReversePermute call")
   242  	}
   243  	lz := bits.LeadingZeros(uint(len(x) - 1))
   244  	i := 0
   245  	for ; i < 3*len(x)/4; i++ {
   246  		j := int(reversePairs(uint(i)) >> lz)
   247  		if i < j {
   248  			x[i], x[j] = x[j], x[i]
   249  		}
   250  	}
   251  	for i++; i < len(x); i += 2 {
   252  		j := int(reversePairs(uint(i)) >> lz)
   253  		if i < j {
   254  			x[i], x[j] = x[j], x[i]
   255  		}
   256  	}
   257  }
   258  
   259  // SequenceRadix4 computes the real periodic sequence from the Fourier
   260  // coefficients, converting the frequency spectrum in coeff into a time
   261  // series, in place and returning it. This transform is unnormalized; a
   262  // call to CoefficientsRadix4 followed by a call of SequenceRadix4 will
   263  // multiply the input sequence by the length of the sequence.
   264  //
   265  // SequenceRadix4 does not allocate, requiring that FFT twiddle factors
   266  // be calculated lazily. For performance reasons, this is done by successive
   267  // multiplication, so numerical accuracies can accumulate for large inputs.
   268  // If accuracy is needed, the FFT or CmplxFFT types should be used.
   269  //
   270  // If the length of coeff is not an integer power of 4, SequenceRadix4
   271  // will panic.
   272  func SequenceRadix4(coeff []complex128) []complex128 {
   273  	x := coeff
   274  	for i, j := 1, len(x)-1; i < j; i, j = i+1, j-1 {
   275  		x[i], x[j] = x[j], x[i]
   276  	}
   277  
   278  	CoefficientsRadix4(x)
   279  	return x
   280  }
   281  
   282  // PadRadix4 returns the values in x in a slice that is an integer
   283  // power of 4 long. If x already has an integer power of 4 length
   284  // it is returned unaltered.
   285  func PadRadix4(x []complex128) []complex128 {
   286  	if len(x) == 0 {
   287  		return x
   288  	}
   289  	b := bits.Len(uint(len(x)))
   290  	if len(x) == 1<<(b-1) && b&0x1 == 1 {
   291  		return x
   292  	}
   293  	p := make([]complex128, 1<<((b+1)&^0x1))
   294  	copy(p, x)
   295  	return p
   296  }
   297  
   298  // TrimRadix4 returns the largest slice of x that is has an integer
   299  // power of 4 length, and a slice holding the remaining elements.
   300  func TrimRadix4(x []complex128) (even, remains []complex128) {
   301  	if len(x) == 0 {
   302  		return x, nil
   303  	}
   304  	n := 1 << ((bits.Len(uint(len(x))) - 1) &^ 0x1)
   305  	return x[:n], x[n:]
   306  }
   307  
   308  // reversePairs returns the value of x with its bit pairs in reversed order.
   309  func reversePairs(x uint) uint {
   310  	if bits.UintSize == 32 {
   311  		return uint(reversePairs32(uint32(x)))
   312  	}
   313  	return uint(reversePairs64(uint64(x)))
   314  }
   315  
   316  const (
   317  	m1 = 0x3333333333333333
   318  	m2 = 0x0f0f0f0f0f0f0f0f
   319  )
   320  
   321  // reversePairs32 returns the value of x with its bit pairs in reversed order.
   322  func reversePairs32(x uint32) uint32 {
   323  	const m = 1<<32 - 1
   324  	x = x>>2&(m1&m) | x&(m1&m)<<2
   325  	x = x>>4&(m2&m) | x&(m2&m)<<4
   326  	return bits.ReverseBytes32(x)
   327  }
   328  
   329  // reversePairs64 returns the value of x with its bit pairs in reversed order.
   330  func reversePairs64(x uint64) uint64 {
   331  	const m = 1<<64 - 1
   332  	x = x>>2&(m1&m) | x&(m1&m)<<2
   333  	x = x>>4&(m2&m) | x&(m2&m)<<4
   334  	return bits.ReverseBytes64(x)
   335  }
   336  
   337  func negi(c complex128) complex128 {
   338  	return cmplx.Conj(swap(c))
   339  }
   340  
   341  func swap(c complex128) complex128 {
   342  	return complex(imag(c), real(c))
   343  }