func FFT3dSpec(c gospec.Context) { signal := Alloc3d(32, 16, 8) for i := range signal { for j := range signal[i] { for k := range signal[i][j] { signal[i][j][k] = complex(float64(i+j+k), float64(-i-j-k)) } } } forward := PlanDft3d(signal, signal, Forward, Estimate) c.Specify("Creating a plan doesn't overwrite an existing array if fftw.Estimate is used.", func() { for i := range signal { for j := range signal[i] { for k := range signal[i][j] { c.Expect(signal[i][j][k], gospec.Equals, complex(float64(i+j+k), float64(-i-j-k))) } } } }) // As long as fx < dx/2, fy < dy/2, and fz < dz/2, where dx,dy,dz are the lengths in // each dimension, there will be 2^n spikes, where n is the number of dimensions. // Each spike will be real and have magnitude equal to dx*dy*dz / 2^n dx := len(signal) fx := float64(dx) / 4 dy := len(signal[0]) fy := float64(dy) / 4 dz := len(signal[0][0]) fz := float64(dz) / 4 for i := range signal { for j := range signal[i] { for k := range signal[i][j] { cosx := math.Cos(float64(i) / float64(dx) * fx * math.Pi * 2) cosy := math.Cos(float64(j) / float64(dy) * fy * math.Pi * 2) cosz := math.Cos(float64(k) / float64(dz) * fz * math.Pi * 2) signal[i][j][k] = complex(cosx*cosy*cosz, 0) } } } forward.Execute() c.Specify("Forward 3d FFT works properly.", func() { for i := range signal { for j := range signal[i] { for k := range signal[i][j] { if (i == int(fx) || i == dx-int(fx)) && (j == int(fy) || j == dy-int(fy)) && (k == int(fz) || k == dz-int(fz)) { c.Expect(real(signal[i][j][k]), gospec.IsWithin(1e-7), float64(dx*dy*dz/8)) c.Expect(imag(signal[i][j][k]), gospec.IsWithin(1e-7), 0.0) } else { c.Expect(real(signal[i][j][k]), gospec.IsWithin(1e-7), 0.0) c.Expect(imag(signal[i][j][k]), gospec.IsWithin(1e-7), 0.0) } } } } }) }
func FFT1dSpec(c gospec.Context) { signal := Alloc1d(16) for i := range signal { signal[i] = complex(float64(i), float64(-i)) } forward := PlanDft1d(signal, signal, Forward, Estimate) c.Specify("Creating a plan doesn't overwrite an existing array if fftw.Estimate is used.", func() { for i := range signal { c.Expect(signal[i], gospec.Equals, complex(float64(i), float64(-i))) } }) // A simple real cosine should result in transform with two spikes, one at S[1] and one at S[-1] // The spikes should be real and have amplitude equal to len(S)/2 (because fftw doesn't normalize) for i := range signal { signal[i] = complex(math.Cos(float64(i)/float64(len(signal))*math.Pi*2), 0) } forward.Execute() c.Specify("Forward 1d FFT works properly.", func() { c.Expect(real(signal[0]), gospec.IsWithin(1e-9), 0.0) c.Expect(imag(signal[0]), gospec.IsWithin(1e-9), 0.0) c.Expect(real(signal[1]), gospec.IsWithin(1e-9), float64(len(signal))/2) c.Expect(imag(signal[1]), gospec.IsWithin(1e-9), 0.0) for i := 2; i < len(signal)-1; i++ { c.Expect(real(signal[i]), gospec.IsWithin(1e-9), 0.0) c.Expect(imag(signal[i]), gospec.IsWithin(1e-9), 0.0) } c.Expect(real(signal[len(signal)-1]), gospec.IsWithin(1e-9), float64(len(signal))/2) c.Expect(imag(signal[len(signal)-1]), gospec.IsWithin(1e-9), 0.0) }) }
func FFT3Spec(c gospec.Context) { signal := NewArray3(32, 16, 8) n0, n1, n2 := signal.Dims() for i := 0; i < n0; i++ { for j := 0; j < n1; j++ { for k := 0; k < n2; k++ { signal.Set(i, j, k, complex(float32(i+j+k), float32(-i-j-k))) } } } // As long as fx < dx/2, fy < dy/2, and fz < dz/2, where dx,dy,dz are the lengths in // each dimension, there will be 2^n spikes, where n is the number of dimensions. // Each spike will be real and have magnitude equal to dx*dy*dz / 2^n dx := n0 fx := float64(dx) / 4 dy := n1 fy := float64(dy) / 4 dz := n2 fz := float64(dz) / 4 for i := 0; i < n0; i++ { for j := 0; j < n1; j++ { for k := 0; k < n2; k++ { cosx := math.Cos(float64(i) / float64(dx) * fx * math.Pi * 2) cosy := math.Cos(float64(j) / float64(dy) * fy * math.Pi * 2) cosz := math.Cos(float64(k) / float64(dz) * fz * math.Pi * 2) signal.Set(i, j, k, complex(float32(cosx*cosy*cosz), 0)) } } } NewPlan3(signal, signal, Forward, Estimate).Execute().Destroy() c.Specify("Forward 3D FFT works properly.", func() { for i := 0; i < n0; i++ { for j := 0; j < n1; j++ { for k := 0; k < n2; k++ { if (i == int(fx) || i == dx-int(fx)) && (j == int(fy) || j == dy-int(fy)) && (k == int(fz) || k == dz-int(fz)) { c.Expect(real(signal.At(i, j, k)), gospec.IsWithin(1e-7), float32(dx*dy*dz/8)) c.Expect(imag(signal.At(i, j, k)), gospec.IsWithin(1e-7), 0.0) } else { c.Expect(real(signal.At(i, j, k)), gospec.IsWithin(1e-7), 0.0) c.Expect(imag(signal.At(i, j, k)), gospec.IsWithin(1e-7), 0.0) } } } } }) }
func FFT2dSpec(c gospec.Context) { signal := Alloc2d(64, 8) for i := range signal { for j := range signal[i] { signal[i][j] = complex(float64(i+j), float64(-i-j)) } } forward := PlanDft2d(signal, signal, Forward, Estimate) c.Specify("Creating a plan doesn't overwrite an existing array if fftw.Estimate is used.", func() { for i := range signal { for j := range signal[i] { c.Expect(signal[i][j], gospec.Equals, complex(float64(i+j), float64(-i-j))) } } }) // As long as fx < dx/2 and fy < dy/2, where dx and dy are the lengths in each dimension, // there will be 2^n spikes, where n is the number of dimensions. Each spike will be // real and have magnitude equal to dx*dy / 2^n dx := len(signal) fx := float64(dx) / 4 dy := len(signal[0]) fy := float64(dy) / 4 for i := range signal { for j := range signal[i] { cosx := math.Cos(float64(i) / float64(dx) * fx * math.Pi * 2) cosy := math.Cos(float64(j) / float64(dy) * fy * math.Pi * 2) signal[i][j] = complex(cosx*cosy, 0) } } forward.Execute() c.Specify("Forward 2d FFT works properly.", func() { for i := range signal { for j := range signal[i] { if (i == int(fx) || i == dx-int(fx)) && (j == int(fy) || j == dy-int(fy)) { c.Expect(real(signal[i][j]), gospec.IsWithin(1e-7), float64(dx*dy/4)) c.Expect(imag(signal[i][j]), gospec.IsWithin(1e-7), 0.0) } else { c.Expect(real(signal[i][j]), gospec.IsWithin(1e-7), 0.0) c.Expect(imag(signal[i][j]), gospec.IsWithin(1e-7), 0.0) } } } }) }
func peakVerifier(s []complex64, c gospec.Context) { c.Expect(real(s[0]), gospec.IsWithin(1e-6), 0.0) c.Expect(imag(s[0]), gospec.IsWithin(1e-6), 0.0) c.Expect(real(s[1]), gospec.IsWithin(1e-6), float32(len(s))/2) c.Expect(imag(s[1]), gospec.IsWithin(1e-6), 0.0) for i := 2; i < len(s)-1; i++ { c.Expect(real(s[i]), gospec.IsWithin(1e-6), 0.0) c.Expect(imag(s[i]), gospec.IsWithin(1e-6), 0.0) } c.Expect(real(s[len(s)-1]), gospec.IsWithin(1e-6), float32(len(s))/2) c.Expect(imag(s[len(s)-1]), gospec.IsWithin(1e-6), 0.0) }
func FFTR2CSpec(c gospec.Context) { signal := make([]float64, 16) F_signal := make([]complex128, 9) for i := range signal { signal[i] = math.Sin(float64(i) / float64(len(signal)) * math.Pi * 2) } forward := PlanDftR2C1d(signal, F_signal, Estimate) forward.Execute() c.Specify("Running a R2C transform doesn't destroy the input.", func() { for i := range signal { c.Expect(signal[i], gospec.Equals, math.Sin(float64(i)/float64(len(signal))*math.Pi*2)) } }) c.Specify("Forward 1d Real to Complex FFT works properly.", func() { c.Expect(real(F_signal[0]), gospec.IsWithin(1e-9), 0.0) c.Expect(imag(F_signal[0]), gospec.IsWithin(1e-9), 0.0) c.Expect(real(F_signal[1]), gospec.IsWithin(1e-9), 0.0) c.Expect(imag(F_signal[1]), gospec.IsWithin(1e-9), -float64(len(signal))/2) for i := 2; i < len(F_signal)-1; i++ { c.Expect(real(F_signal[i]), gospec.IsWithin(1e-9), 0.0) c.Expect(imag(F_signal[i]), gospec.IsWithin(1e-9), 0.0) } }) }
func FFT2Spec(c gospec.Context) { signal := NewArray2(64, 8) n0, n1 := signal.Dims() for i := 0; i < n0; i++ { for j := 0; j < n1; j++ { signal.Set(i, j, complex(float32(i+j), float32(-i-j))) } } // As long as fx < dx/2 and fy < dy/2, where dx and dy are the lengths in each dimension, // there will be 2^n spikes, where n is the number of dimensions. Each spike will be // real and have magnitude equal to dx*dy / 2^n dx := n0 fx := float64(dx) / 4 dy := n1 fy := float64(dy) / 4 for i := 0; i < n0; i++ { for j := 0; j < n1; j++ { cosx := math.Cos(float64(i) / float64(dx) * fx * math.Pi * 2) cosy := math.Cos(float64(j) / float64(dy) * fy * math.Pi * 2) signal.Set(i, j, complex(float32(cosx*cosy), 0)) } } NewPlan2(signal, signal, Forward, Estimate).Execute().Destroy() c.Specify("Forward 2D FFT works properly.", func() { for i := 0; i < n0; i++ { for j := 0; j < n1; j++ { if (i == int(fx) || i == dx-int(fx)) && (j == int(fy) || j == dy-int(fy)) { c.Expect(real(signal.At(i, j)), gospec.IsWithin(1e-7), float32(dx*dy/4)) c.Expect(imag(signal.At(i, j)), gospec.IsWithin(1e-7), 0.0) } else { c.Expect(real(signal.At(i, j)), gospec.IsWithin(1e-7), 0.0) c.Expect(imag(signal.At(i, j)), gospec.IsWithin(1e-7), 0.0) } } } }) }
func FFTC2RSpec(c gospec.Context) { signal := make([]float64, 16) F_signal := make([]complex128, 9) forward := PlanDftR2C1d(signal, F_signal, Estimate) backward := PlanDftC2R1d(F_signal, signal, Estimate) for i := range signal { signal[i] = float64(i) } forward.Execute() backward.Execute() c.Specify("Forward 1d Complx to Real FFT works properly.", func() { for i := 0; i < len(signal); i++ { c.Expect(signal[i], gospec.IsWithin(1e-7), float64(i*len(signal))) } }) }