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 }