Documentation
¶
Overview ¶
Package fft is a pure-Go (cgo-free) fast Fourier transform library — the numpy.fft / scipy.fft equivalent for Go.
It computes the discrete Fourier transform (DFT) of complex and real signals of any length, with no dependency on the native FFTW3 C library. A length whose prime factors are all small uses an iterative mixed-radix (Stockham) engine (radix-8/4/2/3/5/7 straight-line passes plus a general radix-p pass for 11/13), whose radix-2/3/4/5/8 passes run as AVX2 (or, for powers of two, AVX-512) kernels on amd64, bit-identical to the Go passes; a power of two on loong64/s390x, above 65536 on riscv64, or on amd64 without AVX2, uses an iterative radix-4 kernel instead (with SSE2 butterflies on amd64). A prime whose N-1 is 7-smooth uses Rader's algorithm and any other length Bluestein's chirp-z algorithm, so any length transforms correctly and fast. Twiddle factors are precomputed and cached per length (see Plan / NewPlan), so repeated transforms of one length recompute no sin/cos.
The multi-dimensional transforms (FFT2/FFTN and their real and inverse forms) are separable: they apply a 1-D transform along each axis, and the independent lines of a large axis run in parallel across goroutines — a multicore path single-threaded references such as pocketfft cannot take. NewPlanN and NewRealPlan2 build reusable N-D plans that write into the caller's slice and allocate nothing in steady state. See BENCHMARKS.md for the head-to-head benchmarks against FFTW, numpy.fft and scipy.fft.
The forward transform follows the unnormalized convention
X[k] = sum_{n=0}^{N-1} x[n] * exp(-2πi·k·n/N)
and the inverse divides by N, so IFFT(FFT(x)) ≈ x to floating-point tolerance.
RFFT returns only the non-redundant N/2+1 bins of a real signal's spectrum (numpy.fft.rfft) and IRFFT inverts it back to a real signal of a caller-specified length (numpy.fft.irfft). See docs/plan-fft.md for the roadmap.
Fused multiply-add (Options.FMA) ¶
By default every amd64 kernel is bit-identical to the package's Go passes compiled without fused multiply-add, so a result does not depend on which kernel ran. Options{FMA: true} (FFTWith and the other ...With functions, NewPlanWith, NewRealPlanWith, NewPlanNWith, NewRealPlan2With) gives that up for speed on amd64 CPUs with FMA3: every twiddle product between passes, the √2/2 products of the radix-8 butterfly and the internal twiddles of the radix-9 and radix-16 butterflies are fused, as FFTW's FMA codelets fuse them. The results then differ from the default's in the last bits, and are as accurate: against scipy.fft in long double on the same inputs, the relative RMS error of 90 transforms (complex 16 to 2^20, composites, Rader and Bluestein primes, real, inverse and 2-D) was 0.90 to 1.04 times the default's, 1.1e-15 at most (BENCHMARKS.md, Round 41). The float32 transforms ignore the option; elsewhere than amd64 with FMA3 it builds the default plans. Each FMA kernel is bit-identical to a Go reference written with math.FMA, and FMA plans are cached apart from the default ones.
An FMA plan fuses only where fusing was measured to pay (Round 42): on Intel CPUs with the AVX-512 split layout (Cascade Lake) and on AMD CPUs with the AVX2 one (Zen 3), a table gives, per length, the passes that fuse (the others run the default kernels) and, on the former, radix-32 passes for 1,024 and 2,048 points, which only FMA plans have. Elsewhere every pass fuses. A transform of a length the table leaves unfused is the default transform, bit for bit.
Example (RealPlan2_32) ¶
A RealPlan2_32 is the plan behind RFFT2_32 and IRFFT2_32.
p := fft.NewRealPlan2_32(2, 2)
S := p.RFFT(make([]complex64, p.SpectrumLen()), []float32{1, 2, 3, 4})
fmt.Println(tidy(S))
fmt.Println(p.IRFFT(make([]float32, 4), S))
Output: [(10+0i) (-2+0i) (-4+0i) (0+0i)] [1 2 3 4]
Example (Rfft2_32) ¶
RFFT2_32 keeps cols/2+1 bins per row of a float32 image; IRFFT2_32 takes the image's shape back. (A package-level example: go vet reads a name like ExampleRFFT2_32 as an example of a method "32" of RFFT2.)
img := []float32{
1, 2, 3, 4,
5, 6, 7, 8,
}
S := fft.RFFT2_32(img, [2]int{2, 4}) // 2×3 bins
fmt.Println(tidy(S))
fmt.Println(fft.IRFFT2_32(S, [2]int{2, 4}))
Output: [(36+0i) (-4+4i) (-4+0i) (-16+0i) (0+0i) (0+0i)] [1 2 3 4 5 6 7 8]
Index ¶
- func Bartlett(n int) []float64
- func Blackman(n int) []float64
- func BlackmanHarris(n int) []float64
- func DCT(x []float64, typ int, norm Norm) []float64
- func DCT32(x []float32, typ int, norm Norm) []float32
- func DCTN(x []float64, shape []int, typ int, norm Norm) []float64
- func DCTN32(x []float32, shape []int, typ int, norm Norm) []float32
- func DST(x []float64, typ int, norm Norm) []float64
- func DST32(x []float32, typ int, norm Norm) []float32
- func DSTN(x []float64, shape []int, typ int, norm Norm) []float64
- func DSTN32(x []float32, shape []int, typ int, norm Norm) []float32
- func FFT(x []complex128) []complex128
- func FFT2(data []complex128, shape [2]int) []complex128
- func FFT2With(data []complex128, shape [2]int, o Options) []complex128
- func FFT2_32(data []complex64, shape [2]int) []complex64
- func FFT2_32With(data []complex64, shape [2]int, o Options) []complex64
- func FFT32(x []complex64) []complex64
- func FFT32With(x []complex64, o Options) []complex64
- func FFTFreq(n int, d float64) []float64
- func FFTN(data []complex128, shape []int) []complex128
- func FFTN32(data []complex64, shape []int) []complex64
- func FFTN32With(data []complex64, shape []int, o Options) []complex64
- func FFTNWith(data []complex128, shape []int, o Options) []complex128
- func FFTReal(x []float64) []complex128
- func FFTShift[T any](x []T) []T
- func FFTShiftN[T any](x []T, shape []int, axes []int) []T
- func FFTWith(x []complex128, o Options) []complex128
- func HFFT(x []complex128, n int) []float64
- func HFFT32(x []complex64, n int) []float32
- func HFFT32With(x []complex64, o Options) []float32
- func HFFTWith(x []complex128, o Options) []float64
- func Hamming(n int) []float64
- func Hann(n int) []float64
- func IDCT(x []float64, typ int, norm Norm) []float64
- func IDCT32(x []float32, typ int, norm Norm) []float32
- func IDCTN(x []float64, shape []int, typ int, norm Norm) []float64
- func IDCTN32(x []float32, shape []int, typ int, norm Norm) []float32
- func IDST(x []float64, typ int, norm Norm) []float64
- func IDST32(x []float32, typ int, norm Norm) []float32
- func IDSTN(x []float64, shape []int, typ int, norm Norm) []float64
- func IDSTN32(x []float32, shape []int, typ int, norm Norm) []float32
- func IFFT(x []complex128) []complex128
- func IFFT2(data []complex128, shape [2]int) []complex128
- func IFFT2With(data []complex128, shape [2]int, o Options) []complex128
- func IFFT2_32(data []complex64, shape [2]int) []complex64
- func IFFT2_32With(data []complex64, shape [2]int, o Options) []complex64
- func IFFT32(x []complex64) []complex64
- func IFFT32With(x []complex64, o Options) []complex64
- func IFFTN(data []complex128, shape []int) []complex128
- func IFFTN32(data []complex64, shape []int) []complex64
- func IFFTN32With(data []complex64, shape []int, o Options) []complex64
- func IFFTNWith(data []complex128, shape []int, o Options) []complex128
- func IFFTShift[T any](x []T) []T
- func IFFTShiftN[T any](x []T, shape []int, axes []int) []T
- func IFFTWith(x []complex128, o Options) []complex128
- func IHFFT(x []float64) []complex128
- func IHFFT32(x []float32) []complex64
- func IHFFT32With(x []float32, o Options) []complex64
- func IHFFTWith(x []float64, o Options) []complex128
- func IRFFT(spectrum []complex128, n int) []float64
- func IRFFT2(data []complex128, shape [2]int) []float64
- func IRFFT2With(data []complex128, shape [2]int, o Options) []float64
- func IRFFT2_32(data []complex64, shape [2]int) []float32
- func IRFFT2_32With(data []complex64, shape [2]int, o Options) []float32
- func IRFFT32(spectrum []complex64, n int) []float32
- func IRFFT32With(spectrum []complex64, o Options) []float32
- func IRFFTN(data []complex128, shape []int) []float64
- func IRFFTN32(data []complex64, shape []int) []float32
- func IRFFTN32With(data []complex64, shape []int, o Options) []float32
- func IRFFTNWith(data []complex128, shape []int, o Options) []float64
- func IRFFTWith(spectrum []complex128, o Options) []float64
- func NextFastLen(target int, real bool) int
- func PSD(x []float64, d float64) []float64
- func RFFT(x []float64) []complex128
- func RFFT2(data []float64, shape [2]int) []complex128
- func RFFT2With(data []float64, shape [2]int, o Options) []complex128
- func RFFT2_32(data []float32, shape [2]int) []complex64
- func RFFT2_32With(data []float32, shape [2]int, o Options) []complex64
- func RFFT32(x []float32) []complex64
- func RFFT32With(x []float32, o Options) []complex64
- func RFFTFreq(n int, d float64) []float64
- func RFFTN(data []float64, shape []int) []complex128
- func RFFTN32(data []float32, shape []int) []complex64
- func RFFTN32With(data []float32, shape []int, o Options) []complex64
- func RFFTNWith(data []float64, shape []int, o Options) []complex128
- func RFFTWith(x []float64, o Options) []complex128
- func Spectrogram(x []float64, segment, overlap int, window []float64, d float64) [][]float64
- type DCTPlan
- type DCTPlan32
- type DSTPlan
- type DSTPlan32
- type Norm
- type Options
- type Plan
- type Plan32
- type PlanN
- func (p *PlanN) FFT(dst, src []complex128) []complex128
- func (p *PlanN) FFTNorm(dst, src []complex128, m Norm) []complex128
- func (p *PlanN) IFFT(dst, src []complex128) []complex128
- func (p *PlanN) IFFTNorm(dst, src []complex128, m Norm) []complex128
- func (p *PlanN) Len() int
- func (p *PlanN) Shape() []int
- type PlanN32
- func (p *PlanN32) FFT(dst, src []complex64) []complex64
- func (p *PlanN32) FFTNorm(dst, src []complex64, m Norm) []complex64
- func (p *PlanN32) IFFT(dst, src []complex64) []complex64
- func (p *PlanN32) IFFTNorm(dst, src []complex64, m Norm) []complex64
- func (p *PlanN32) Len() int
- func (p *PlanN32) Shape() []int
- type RealPlan
- func (p *RealPlan) IRFFT(dst []float64, src []complex128) []float64
- func (p *RealPlan) IRFFTNorm(dst []float64, src []complex128, m Norm) []float64
- func (p *RealPlan) Len() int
- func (p *RealPlan) RFFT(dst []complex128, src []float64) []complex128
- func (p *RealPlan) RFFTNorm(dst []complex128, src []float64, m Norm) []complex128
- type RealPlan2
- func (p *RealPlan2) IRFFT(dst []float64, src []complex128) []float64
- func (p *RealPlan2) IRFFTNorm(dst []float64, src []complex128, m Norm) []float64
- func (p *RealPlan2) RFFT(dst []complex128, src []float64) []complex128
- func (p *RealPlan2) RFFTNorm(dst []complex128, src []float64, m Norm) []complex128
- func (p *RealPlan2) SpectrumLen() int
- type RealPlan2_32
- func (p *RealPlan2_32) IRFFT(dst []float32, src []complex64) []float32
- func (p *RealPlan2_32) IRFFTNorm(dst []float32, src []complex64, m Norm) []float32
- func (p *RealPlan2_32) RFFT(dst []complex64, src []float32) []complex64
- func (p *RealPlan2_32) RFFTNorm(dst []complex64, src []float32, m Norm) []complex64
- func (p *RealPlan2_32) SpectrumLen() int
- type RealPlan32
- func (p *RealPlan32) IRFFT(dst []float32, src []complex64) []float32
- func (p *RealPlan32) IRFFTNorm(dst []float32, src []complex64, norm Norm) []float32
- func (p *RealPlan32) Len() int
- func (p *RealPlan32) RFFT(dst []complex64, src []float32) []complex64
- func (p *RealPlan32) RFFTNorm(dst []complex64, src []float32, norm Norm) []complex64
Examples ¶
- Package (RealPlan2_32)
- Package (Rfft2_32)
- DCT
- DCT32
- DCTN
- DST
- FFT2With
- FFT32
- FFT32With
- FFTN32
- FFTNWith
- FFTShift
- FFTShiftN
- FFTWith
- HFFT
- HFFTWith
- IFFT2With
- IFFTNWith
- IFFTShift
- IFFTShiftN
- IFFTWith
- IHFFT
- IHFFTWith
- IRFFT2With
- IRFFTN
- IRFFTNWith
- IRFFTWith
- NewDCTPlan
- NextFastLen
- Options
- Plan32.FFTNorm
- Plan.FFTNorm
- Plan.IFFTNorm
- PlanN32
- PlanN.FFTNorm
- PlanN.IFFTNorm
- RFFT2With
- RFFT32
- RFFTN
- RFFTN32With
- RFFTNWith
- RFFTWith
- RealPlan2.IRFFTNorm
- RealPlan2.RFFTNorm
- RealPlan32
- RealPlan.IRFFTNorm
- RealPlan.RFFTNorm
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Bartlett ¶
Bartlett returns the length-n Bartlett (triangular) window:
w[k] = (2/(n-1)) · ((n-1)/2 - |k - (n-1)/2|), k = 0 .. n-1,
which rises linearly from 0 to 1 at the center and back to 0. This matches numpy.bartlett(n).
func Blackman ¶
Blackman returns the length-n Blackman window:
w[k] = 0.42 - 0.5·cos(2π·k/(n-1)) + 0.08·cos(4π·k/(n-1)).
This matches numpy.blackman(n).
func BlackmanHarris ¶
BlackmanHarris returns the length-n (4-term) Blackman–Harris window with the standard coefficients a0..a3 = 0.35875, 0.48829, 0.14128, 0.01168:
w[k] = a0 - a1·cos(2π·k/(n-1)) + a2·cos(4π·k/(n-1)) - a3·cos(6π·k/(n-1)).
This matches scipy.signal.windows.blackmanharris(n, sym=True).
func DCT ¶ added in v0.5.0
DCT returns the discrete cosine transform of type typ (1, 2, 3 or 4) of x, scaled by norm, as scipy.fft.dct(x, type=typ, norm=norm). The definitions are those of scipy (see the DCTPlan methods); NormOrtho also applies scipy's default orthogonalisation. x is not modified.
It panics if typ is not 1..4, if len(x) is below the type's minimum (2 for DCT-I, 1 otherwise) or if norm is unknown.
Example ¶
The DCT-II with norm="ortho" is MATLAB's dct and the transform JPEG uses; a smooth signal packs its energy into the first coefficients.
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round4 rounds to 4 decimals and turns the rounding residue of an exact zero
// (which may print as -0.0000 on one architecture and 0.0000 on another) into 0.
func round4(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = math.Round(v*1e4) / 1e4
if out[i] == 0 {
out[i] = 0
}
}
return out
}
func main() {
x := []float64{1, 2, 3, 4}
y := fft.DCT(x, 2, fft.NormOrtho)
fmt.Println(round4(y))
fmt.Println(round4(fft.IDCT(y, 2, fft.NormOrtho)))
}
Output: [5 -2.2304 0 -0.1585] [1 2 3 4]
func DCT32 ¶ added in v0.9.0
DCT32 returns the DCT of type typ (1, 2, 3 or 4) of the float32 signal x, scaled by norm, in single precision: scipy.fft.dct(x, type=typ, norm=norm) for a float32 x, which scipy returns as float32. x is not modified. The same panics as DCT apply.
Example ¶
DCT32 is scipy.fft.dct on float32 input; with NormOrtho, IDCT32 undoes it.
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round4f32 rounds v to four decimals for printing, with positive zeros: a value
// that cancels exactly, or rounds to zero, may carry either sign depending on
// the CPU's fused multiply-add, and the sign carries no information here.
func round4f32(v []float32) []float64 {
out := make([]float64, len(v))
for i, x := range v {
out[i] = math.Round(float64(x)*1e4)/1e4 + 0
}
return out
}
func main() {
x := []float32{1, 2, 3, 4}
y := fft.DCT32(x, 2, fft.NormOrtho)
fmt.Println(round4f32(y))
fmt.Println(round4f32(fft.IDCT32(y, 2, fft.NormOrtho)))
}
Output: [5 -2.2304 0 -0.1585] [1 2 3 4]
func DCTN ¶ added in v0.5.0
DCTN returns the N-dimensional DCT of type typ of x, a row-major array of the given shape, as scipy.fft.dctn(x, type=typ, norm=norm). x is not modified. It panics if the shape does not match len(x), if an axis is below the type's minimum length, or on an unknown type or norm.
Example ¶
DCTN transforms every axis of a row-major array.
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round4 rounds to 4 decimals and turns the rounding residue of an exact zero
// (which may print as -0.0000 on one architecture and 0.0000 on another) into 0.
func round4(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = math.Round(v*1e4) / 1e4
if out[i] == 0 {
out[i] = 0
}
}
return out
}
func main() {
img := []float64{
1, 1, 1,
1, 1, 1,
}
fmt.Println(round4(fft.DCTN(img, []int{2, 3}, 2, fft.NormOrtho)))
}
Output: [2.4495 0 0 0 0 0]
func DCTN32 ¶ added in v0.9.0
DCTN32 is DCTN in single precision: the DCT of type typ along every axis of the row-major float32 array x, as scipy.fft.dctn(x, type=typ, norm=norm). The same rules as DCTN apply.
func DST ¶ added in v0.5.0
DST returns the discrete sine transform of type typ (1, 2, 3 or 4) of x, scaled by norm, as scipy.fft.dst(x, type=typ, norm=norm); NormOrtho also applies scipy's default orthogonalisation. x is not modified.
It panics if typ is not 1..4, if x is empty or if norm is unknown.
Example ¶
The DST-I diagonalises the second-difference operator with zero boundary values: a sine mode is one coefficient.
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round4 rounds to 4 decimals and turns the rounding residue of an exact zero
// (which may print as -0.0000 on one architecture and 0.0000 on another) into 0.
func round4(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = math.Round(v*1e4) / 1e4
if out[i] == 0 {
out[i] = 0
}
}
return out
}
func main() {
x := []float64{0.5, 0.8660254037844386, 1, 0.8660254037844386, 0.5} // sin(π(n+1)/6)
fmt.Println(round4(fft.DST(x, 1, fft.NormBackward)))
}
Output: [6 0 0 0 0]
func DST32 ¶ added in v0.9.0
DST32 returns the DST of type typ (1, 2, 3 or 4) of x in single precision, as scipy.fft.dst(x, type=typ, norm=norm) for a float32 x. The same panics as DST apply.
func DSTN ¶ added in v0.5.0
DSTN returns the N-dimensional DST of type typ of x, a row-major array of the given shape, as scipy.fft.dstn(x, type=typ, norm=norm). The same rules as DCTN apply.
func DSTN32 ¶ added in v0.9.0
DSTN32 is DSTN in single precision, as scipy.fft.dstn(x, type=typ, norm=norm). The same rules as DCTN apply.
func FFT ¶
func FFT(x []complex128) []complex128
FFT returns the forward discrete Fourier transform of x, using the unnormalized convention
X[k] = sum_{n=0}^{N-1} x[n] * exp(-2πi·k·n/N).
Highly-composite lengths (whose prime factors are all small) use mixed-radix Cooley–Tukey; a length with a large prime factor falls back to Bluestein's chirp-z algorithm. Twiddle factors are cached per length in an internal plan cache, so repeated transforms of the same length recompute no sin/cos. The input is not modified. Empty input returns an empty (non-nil) slice; length 1 returns a copy.
func FFT2 ¶
func FFT2(data []complex128, shape [2]int) []complex128
FFT2 is the two-dimensional FFTN: it transforms data as a row-major shape[0]×shape[1] matrix (rows then columns), matching numpy.fft.fft2.
func FFT2With ¶ added in v0.4.0
func FFT2With(data []complex128, shape [2]int, o Options) []complex128
FFT2With is FFT2 with numpy.fft.fft2's axes and norm arguments: FFTNWith on a two-axis shape.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
x := []complex128{1, 1, 1, 1}
fmt.Println(roundC(fft.FFT2With(x, [2]int{2, 2}, fft.Options{Norm: fft.NormOrtho})))
}
Output: [(2+0i) (0+0i) (0+0i) (0+0i)]
func FFT2_32 ¶ added in v0.9.0
FFT2_32 is the two-dimensional FFTN32: FFT2 in single precision (scipy.fft.fft2 on complex64 input).
func FFT2_32With ¶ added in v0.9.0
FFT2_32With is FFT2_32 with numpy.fft.fft2's axes and norm arguments: FFTN32With on a two-axis shape.
func FFT32 ¶ added in v0.6.0
FFT32 returns the forward discrete Fourier transform of x in single precision, unnormalized like FFT. The input is not modified; empty input returns an empty (non-nil) slice. Plans are cached per length.
Example ¶
FFT32 and IFFT32 are FFT and IFFT for complex64 data.
package main
import (
"fmt"
"github.com/go-fft/fft"
)
// tidy turns the zeros of v positive for printing: whether an exactly
// cancelling sum comes out +0 or -0 depends on the CPU's fused multiply-add
// (loong64 and amd64 differ), and the sign of zero carries no information here.
func tidy(v []complex64) []complex64 {
out := make([]complex64, len(v))
for i, z := range v {
out[i] = complex(real(z)+0, imag(z)+0)
}
return out
}
func main() {
x := []complex64{1, 2, 3, 4}
X := fft.FFT32(x)
fmt.Println(tidy(X))
fmt.Println(tidy(fft.IFFT32(X)))
}
Output: [(10+0i) (-2+2i) (-2+0i) (-2-2i)] [(1+0i) (2+0i) (3+0i) (4+0i)]
func FFT32With ¶ added in v0.9.0
FFT32With is FFT32 with numpy.fft.fft's n and norm arguments, as FFTWith: the input is truncated or zero-padded to o.N points (len(x) when o.N is zero) and the transform is scaled as o.Norm says. The input is not modified. o.Axes must be nil.
Example ¶
The Options of the float64 transforms apply unchanged: here numpy's n (zero-padding to 4 points) and norm="forward".
x := []complex64{4, 4}
X := fft.FFT32With(x, fft.Options{N: 4, Norm: fft.NormForward})
fmt.Println(tidy(X))
Output: [(2+0i) (1-1i) (0+0i) (1+1i)]
func FFTFreq ¶
FFTFreq returns the n sample frequencies of an FFT of length n, given the sample spacing d (the inverse of the sampling rate). The result matches numpy.fft.fftfreq(n, d) exactly:
f = [0, 1, ..., (n-1)//2, -(n//2), ..., -1] / (d·n).
The DC bin is first, then the positive frequencies in increasing order, then the negative frequencies. For even n the Nyquist bin appears as -n/2; for odd n the largest positive bin is (n-1)/2. n <= 0 returns an empty (non-nil) slice.
func FFTN ¶
func FFTN(data []complex128, shape []int) []complex128
FFTN returns the forward N-dimensional discrete Fourier transform of data, interpreted as a row-major (C-order) array of the given shape. The result is a new slice of the same length; the input is not modified.
The transform is separable and unnormalized: it applies the 1-D FFT along each axis in turn, matching numpy.fft.fftn. shape must contain only positive lengths whose product equals len(data); FFTN panics otherwise (consistent with numpy raising on a mismatched shape). An empty shape transforms the single scalar unchanged.
func FFTN32 ¶ added in v0.9.0
FFTN32 returns the forward N-dimensional DFT of the complex64 row-major array data of the given shape, in single precision and unnormalized, like FFTN (scipy.fft.fftn on complex64 input). The input is not modified; the same shape rules as FFTN apply.
Example ¶
FFTN32 and IFFTN32 are FFTN and IFFTN for complex64 data; FFT2_32 is the two-axis case (the underscore keeps "2" and "32" apart).
x := []complex64{1, 2, 3, 4} // a 2×2 matrix, row-major
X := fft.FFTN32(x, []int{2, 2})
fmt.Println(tidy(X))
fmt.Println(tidy(fft.FFT2_32(x, [2]int{2, 2})))
fmt.Println(tidy(fft.IFFTN32(X, []int{2, 2})))
Output: [(10+0i) (-2+0i) (-4+0i) (0+0i)] [(10+0i) (-2+0i) (-4+0i) (0+0i)] [(1+0i) (2+0i) (3+0i) (4+0i)]
func FFTN32With ¶ added in v0.9.0
FFTN32With is FFTN32 with numpy.fft.fftn's axes and norm arguments, as FFTNWith: only the axes in o.Axes are transformed (every axis when nil) and the result is scaled as o.Norm says. o.N must be zero.
func FFTNWith ¶ added in v0.4.0
func FFTNWith(data []complex128, shape []int, o Options) []complex128
FFTNWith is FFTN with numpy.fft.fftn's axes and norm arguments: data is a row-major array of the given shape, only the axes in o.Axes are transformed (every axis when o.Axes is nil), and the result is scaled as o.Norm says. FFTNWith(data, shape, Options{}) equals FFTN(data, shape). The output has the input's shape; the input is not modified. o.N must be zero.
With o.Axes = []int{-1} it is the batched 1-D transform: every row of a matrix of signals is transformed with one plan.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
// Three signals of four points, one per row: transforming the last axis
// alone is numpy's fft(x, axis=-1), the batched 1-D transform.
rows := []complex128{
1, 0, 0, 0,
1, 1, 1, 1,
0, 1, 0, 0,
}
out := fft.FFTNWith(rows, []int{3, 4}, fft.Options{Axes: []int{-1}})
for r := 0; r < 3; r++ {
fmt.Println(roundC(out[r*4 : (r+1)*4]))
}
}
Output: [(1+0i) (1+0i) (1+0i) (1+0i)] [(4+0i) (0+0i) (0+0i) (0+0i)] [(1+0i) (0-1i) (-1+0i) (0+1i)]
func FFTReal ¶
func FFTReal(x []float64) []complex128
FFTReal returns the forward discrete Fourier transform of a real-valued signal as the full complex spectrum (length len(x)). It is a convenience wrapper that promotes x to complex128 and calls FFT.
func FFTShift ¶ added in v0.4.0
func FFTShift[T any](x []T) []T
FFTShift returns x with its zero-frequency element moved to the centre: x rotated right by len(x)/2, numpy.fft.fftshift on a 1-D array. For FFTFreq(n, d) it returns the frequencies in increasing order. The input is not modified; the result is a new slice (empty, not nil, for empty input).
Example ¶
package main
import (
"fmt"
"github.com/go-fft/fft"
)
func main() {
// Bin frequencies in increasing order, the zero frequency in the middle.
fmt.Println(fft.FFTShift(fft.FFTFreq(5, 1)))
fmt.Println(fft.FFTShift([]int{0, 1, 2, 3, 4, 5}))
}
Output: [-0.4 -0.2 0 0.2 0.4] [3 4 5 0 1 2]
func FFTShiftN ¶ added in v0.4.0
FFTShiftN is numpy.fft.fftshift on a row-major array of the given shape: every axis in axes (every axis when axes is nil; negative axes count from the end) is rotated by its length/2, which moves the zero-frequency bin of an N-D spectrum to the centre. shape must hold positive lengths whose product is len(x), and an axis may not be listed twice; FFTShiftN panics otherwise. The input is not modified.
Example ¶
package main
import (
"fmt"
"github.com/go-fft/fft"
)
func main() {
x := []int{
0, 1, 2,
3, 4, 5,
6, 7, 8,
}
fmt.Println(fft.FFTShiftN(x, []int{3, 3}, nil))
fmt.Println(fft.FFTShiftN(x, []int{3, 3}, []int{-1})) // the rows only
}
Output: [8 6 7 2 0 1 5 3 4] [2 0 1 5 3 4 8 6 7]
func FFTWith ¶ added in v0.4.0
func FFTWith(x []complex128, o Options) []complex128
FFTWith is FFT with numpy.fft.fft's n and norm arguments: the input is truncated or zero-padded to o.N points (len(x) when o.N is zero) and the forward transform is scaled as o.Norm says. FFTWith(x, Options{}) equals FFT(x). The input is not modified. o.Axes must be nil.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
x := []complex128{1, 1, 1, 1, 1, 1}
// Truncate to 4 points and scale by 1/sqrt(4) (numpy norm="ortho").
fmt.Println(roundC(fft.FFTWith(x, fft.Options{N: 4, Norm: fft.NormOrtho})))
}
Output: [(2+0i) (0+0i) (0+0i) (0+0i)]
func HFFT ¶ added in v0.4.0
func HFFT(x []complex128, n int) []float64
HFFT returns the DFT of a signal with Hermitian symmetry, given its first half x (x[0] .. x[n/2]; the rest is conj(x[n-k])), as a real slice of n values: numpy.fft.hfft(x, n). It is the forward transform, unscaled:
X[k] = sum_{j=0}^{n-1} y[j] * exp(-2πi·k·j/n), y[j] = x[j], y[n-j] = conj(x[j]).
numpy defines it as irfft(conj(x), n) multiplied by n; HFFT computes the same. n is the length of the output, as for IRFFT (n and n-1 share the same half); n <= 0 returns an empty slice. x is read up to n/2+1 values and missing ones are zero. The input is not modified.
See https://numpy.org/doc/stable/reference/generated/numpy.fft.hfft.html.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundR(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = round(v)
}
return out
}
func main() {
// The first half of a Hermitian-symmetric signal y = [1, 2, 3, 2]; its DFT
// is real.
fmt.Println(roundR(fft.HFFT([]complex128{1, 2, 3}, 4)))
}
Output: [8 -2 0 -2]
func HFFT32 ¶ added in v0.9.0
HFFT32 is HFFT in single precision: the real DFT, of n points, of the Hermitian-symmetric signal whose first half is x (numpy.fft.hfft(x, n)). n <= 0 returns an empty slice. The input is not modified.
func HFFT32With ¶ added in v0.9.0
HFFT32With is HFFTWith in single precision: o.N is the output length (zero selects 2*(len(x)-1)) and o.Norm scales it as a forward transform. o.Axes must be nil.
func HFFTWith ¶ added in v0.4.0
func HFFTWith(x []complex128, o Options) []float64
HFFTWith is HFFT with numpy.fft.hfft's n and norm arguments: o.N is the length of the real output (zero selects numpy's default 2*(len(x)-1)) and o.Norm scales it as a FORWARD transform — unscaled under the default NormBackward, 1/sqrt(n) under NormOrtho, 1/n under NormForward. numpy implements this as irfft(conj(x), n, norm=<the opposite direction>), which is the same thing. o.Axes must be nil.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundR(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = round(v)
}
return out
}
func main() {
// The same transform scaled as a forward transform under NormForward: 1/n.
fmt.Println(roundR(fft.HFFTWith([]complex128{1, 2, 3}, fft.Options{N: 4, Norm: fft.NormForward})))
}
Output: [2 -0.5 0 -0.5]
func Hamming ¶
Hamming returns the length-n Hamming window:
w[k] = 0.54 - 0.46·cos(2π·k/(n-1)), k = 0 .. n-1.
This matches numpy.hamming(n).
func Hann ¶
Hann returns the length-n Hann (Hanning) window:
w[k] = 0.5 - 0.5·cos(2π·k/(n-1)), k = 0 .. n-1.
This matches numpy.hanning(n).
func IDCT ¶ added in v0.5.0
IDCT returns the inverse discrete cosine transform of type typ of x, as scipy.fft.idct(x, type=typ, norm=norm), so that IDCT(DCT(x, t, m), t, m) reproduces x. The same panics as DCT apply.
func IDCT32 ¶ added in v0.9.0
IDCT32 returns the inverse DCT of type typ of x in single precision, as scipy.fft.idct(x, type=typ, norm=norm). The same panics as DCT apply.
func IDST ¶ added in v0.5.0
IDST returns the inverse discrete sine transform of type typ of x, as scipy.fft.idst(x, type=typ, norm=norm), so that IDST(DST(x, t, m), t, m) reproduces x. The same panics as DST apply.
func IDST32 ¶ added in v0.9.0
IDST32 returns the inverse DST of type typ of x in single precision, as scipy.fft.idst(x, type=typ, norm=norm). The same panics as DST apply.
func IFFT ¶
func IFFT(x []complex128) []complex128
IFFT returns the inverse discrete Fourier transform of x, normalized by N so that IFFT(FFT(x)) ≈ x to floating-point tolerance:
x[n] = (1/N) * sum_{k=0}^{N-1} X[k] * exp(+2πi·k·n/N).
The input is not modified.
func IFFT2 ¶
func IFFT2(data []complex128, shape [2]int) []complex128
IFFT2 is the two-dimensional IFFTN, the inverse of FFT2, normalized by shape[0]*shape[1]. It matches numpy.fft.ifft2.
func IFFT2With ¶ added in v0.4.0
func IFFT2With(data []complex128, shape [2]int, o Options) []complex128
IFFT2With is IFFT2 with numpy.fft.ifft2's axes and norm arguments: IFFTNWith on a two-axis shape.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
X := []complex128{2, 0, 0, 0}
fmt.Println(roundC(fft.IFFT2With(X, [2]int{2, 2}, fft.Options{Norm: fft.NormOrtho})))
}
Output: [(1+0i) (1+0i) (1+0i) (1+0i)]
func IFFT2_32 ¶ added in v0.9.0
IFFT2_32 is the two-dimensional IFFTN32, the inverse of FFT2_32, normalized by shape[0]*shape[1].
func IFFT2_32With ¶ added in v0.9.0
IFFT2_32With is IFFT2_32 with numpy.fft.ifft2's axes and norm arguments: IFFTN32With on a two-axis shape.
func IFFT32 ¶ added in v0.6.0
IFFT32 returns the inverse discrete Fourier transform of x in single precision, normalized by N like IFFT. The input is not modified.
func IFFT32With ¶ added in v0.9.0
IFFT32With is IFFT32 with numpy.fft.ifft's n and norm arguments, as IFFTWith (1/n under the default NormBackward). o.Axes must be nil.
func IFFTN ¶
func IFFTN(data []complex128, shape []int) []complex128
IFFTN returns the inverse N-dimensional discrete Fourier transform of data, the inverse of FFTN. It applies the 1-D IFFT along each axis, so the result is normalized by the product of the transformed axis lengths and IFFTN(FFTN(x), shape) ≈ x. The input is not modified; the same shape rules as FFTN apply.
func IFFTN32 ¶ added in v0.9.0
IFFTN32 returns the inverse N-dimensional DFT of data in single precision, normalized by the product of the shape, like IFFTN. The input is not modified.
func IFFTN32With ¶ added in v0.9.0
IFFTN32With is IFFTN32 with numpy.fft.ifftn's axes and norm arguments; see FFTN32With.
func IFFTNWith ¶ added in v0.4.0
func IFFTNWith(data []complex128, shape []int, o Options) []complex128
IFFTNWith is IFFTN with numpy.fft.ifftn's axes and norm arguments; see FFTNWith. Under the default NormBackward the result is divided by the product of the transformed axis lengths.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
X := []complex128{4, 0, 0, 0}
// Inverse along axis 0 only, of a 2×2 array.
fmt.Println(roundC(fft.IFFTNWith(X, []int{2, 2}, fft.Options{Axes: []int{0}})))
}
Output: [(2+0i) (0+0i) (2+0i) (0+0i)]
func IFFTShift ¶ added in v0.4.0
func IFFTShift[T any](x []T) []T
IFFTShift is the inverse of FFTShift: x rotated left by len(x)/2, numpy.fft.ifftshift on a 1-D array. IFFTShift(FFTShift(x)) == x for every length; for an even length the two functions coincide. The input is not modified.
Example ¶
package main
import (
"fmt"
"github.com/go-fft/fft"
)
func main() {
shifted := fft.FFTShift([]int{0, 1, 2, 3, 4})
fmt.Println(shifted, fft.IFFTShift(shifted))
}
Output: [3 4 0 1 2] [0 1 2 3 4]
func IFFTShiftN ¶ added in v0.4.0
IFFTShiftN is numpy.fft.ifftshift on a row-major array of the given shape, the inverse of FFTShiftN: every axis in axes (every axis when nil) is rotated back by its length/2. The same rules as FFTShiftN apply.
Example ¶
package main
import (
"fmt"
"github.com/go-fft/fft"
)
func main() {
x := []int{0, 1, 2, 3, 4, 5}
s := fft.FFTShiftN(x, []int{2, 3}, nil)
fmt.Println(s, fft.IFFTShiftN(s, []int{2, 3}, nil))
}
Output: [5 3 4 2 0 1] [0 1 2 3 4 5]
func IFFTWith ¶ added in v0.4.0
func IFFTWith(x []complex128, o Options) []complex128
IFFTWith is IFFT with numpy.fft.ifft's n and norm arguments: the input is truncated or zero-padded to o.N points (len(x) when o.N is zero) and the inverse transform is scaled as o.Norm says (1/n under the default NormBackward). IFFTWith(x, Options{}) equals IFFT(x). The input is not modified. o.Axes must be nil.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
X := []complex128{4, 0, 0, 0}
// Under NormForward the inverse is unscaled.
fmt.Println(roundC(fft.IFFTWith(X, fft.Options{Norm: fft.NormForward})))
}
Output: [(4+0i) (4+0i) (4+0i) (4+0i)]
func IHFFT ¶ added in v0.4.0
func IHFFT(x []float64) []complex128
IHFFT is the inverse of HFFT: it returns the first n/2+1 values of the Hermitian-symmetric signal whose real DFT is x (n = len(x)), normalized by 1/n — numpy.fft.ihfft(x), which numpy defines as conj(rfft(x))/n. Empty input returns an empty slice. The input is not modified.
See https://numpy.org/doc/stable/reference/generated/numpy.fft.ihfft.html.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
// IHFFT inverts HFFT: back to the half signal.
fmt.Println(roundC(fft.IHFFT([]float64{8, -2, 0, -2})))
}
Output: [(1+0i) (2+0i) (3+0i)]
func IHFFT32 ¶ added in v0.9.0
IHFFT32 is IHFFT in single precision: the first n/2+1 values of the Hermitian signal whose real DFT is x, normalized by 1/n (numpy.fft.ihfft(x)). The input is not modified.
func IHFFT32With ¶ added in v0.9.0
IHFFT32With is IHFFTWith in single precision: the input is truncated or zero-padded to o.N points (len(x) when zero) and o.Norm scales the result as an inverse transform. o.Axes must be nil.
func IHFFTWith ¶ added in v0.4.0
func IHFFTWith(x []float64, o Options) []complex128
IHFFTWith is IHFFT with numpy.fft.ihfft's n and norm arguments: the input is truncated or zero-padded to o.N points (len(x) when o.N is zero) and o.Norm scales the result as an INVERSE transform — 1/n under the default NormBackward, 1/sqrt(n) under NormOrtho, unscaled under NormForward — so that HFFTWith(IHFFTWith(x, o), Options{N: len(x), Norm: o.Norm}) ≈ x for every o.Norm. o.Axes must be nil.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundR(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = round(v)
}
return out
}
func main() {
x := []float64{8, -2, 0, -2}
h := fft.IHFFTWith(x, fft.Options{Norm: fft.NormOrtho})
// The pair round-trips under any Norm, given the same one both ways.
fmt.Println(roundR(fft.HFFTWith(h, fft.Options{N: len(x), Norm: fft.NormOrtho})))
}
Output: [8 -2 0 -2]
func IRFFT ¶
func IRFFT(spectrum []complex128, n int) []float64
IRFFT inverts RFFT, reconstructing a real-valued signal of length n from the n/2+1 non-redundant spectral bins produced by RFFT. The caller passes the desired output length n explicitly, because n and n-1 yield the same number of kept bins so the half spectrum alone is ambiguous; this mirrors numpy.fft.irfft(spectrum, n).
spectrum is read up to min(len(spectrum), n/2+1) bins; any bins beyond that (or beyond what the Hermitian mirror needs) are treated as zero. The result is normalized by n so that IRFFT(RFFT(x), len(x)) ≈ x.
The input is not modified. n <= 0 returns an empty (non-nil) slice.
The output has n values whatever the spectrum's length, so n sets the allocation, as it would for make: bound it when it comes from untrusted input (see SECURITY.md).
func IRFFT2 ¶
func IRFFT2(data []complex128, shape [2]int) []float64
IRFFT2 inverts RFFT2, reconstructing a real row-major matrix of shape shape[0]×shape[1] from a spectrum laid out as shape[0]×(shape[1]/2+1) complex bins (the layout RFFT2 produces). The complex inverse is applied down the columns first, then the real inverse (irfft) along each row, with the target row length shape[1] supplied explicitly (since shape[1] and shape[1]-1 share a bin count). The result is normalized by shape[0]*shape[1] so that IRFFT2(RFFT2(x, shape), shape) ≈ x. This matches numpy.fft.irfft2.
shape lengths must be positive; IRFFT2 panics otherwise. data is read up to shape[0]*(shape[1]/2+1) bins; any beyond that are treated as zero. The input is not modified. The output has shape[0]*shape[1] values whatever the spectrum's length: bound the shape when it comes from untrusted input (see SECURITY.md).
func IRFFT2With ¶ added in v0.4.0
func IRFFT2With(data []complex128, shape [2]int, o Options) []float64
IRFFT2With is IRFFT2 with numpy.fft.irfft2's axes and norm arguments. With o.Axes nil it runs IRFFT2's plan and rescales the result; with axes it is IRFFTNWith on a two-axis shape.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundR(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = round(v)
}
return out
}
func main() {
spec := []complex128{1, 0, 0, 0}
fmt.Println(roundR(fft.IRFFT2With(spec, [2]int{2, 2}, fft.Options{Norm: fft.NormForward})))
}
Output: [1 1 1 1]
func IRFFT2_32 ¶ added in v0.9.0
IRFFT2_32 inverts RFFT2_32, as IRFFT2 inverts RFFT2: shape is the real output's, data is read up to shape[0]*(shape[1]/2+1) bins (missing ones are zero) and the result is normalized by shape[0]*shape[1]. The output has shape[0]*shape[1] values whatever the spectrum's length: bound the shape when it comes from untrusted input (see SECURITY.md).
func IRFFT2_32With ¶ added in v0.9.0
IRFFT2_32With is IRFFT2_32 with numpy.fft.irfft2's axes and norm arguments. With o.Axes nil it runs IRFFT2_32's plan; with axes it is IRFFTN32With on a two-axis shape.
func IRFFT32 ¶ added in v0.6.0
IRFFT32 inverts RFFT32, returning n real samples normalized by n like IRFFT. n <= 0 returns an empty (non-nil) slice. n sets the allocation: bound it when it comes from untrusted input (see SECURITY.md).
func IRFFT32With ¶ added in v0.9.0
IRFFT32With is IRFFT32 with numpy.fft.irfft's n and norm arguments, as IRFFTWith: o.N is the length of the real output, zero selecting numpy's default 2*(len(spectrum)-1). o.Axes must be nil. The output length is the caller's o.N whatever the spectrum's length: bound it when it comes from untrusted input (see SECURITY.md).
func IRFFTN ¶ added in v0.4.0
func IRFFTN(data []complex128, shape []int) []float64
IRFFTN inverts RFFTN: shape is the shape of the REAL output (its last length n cannot be recovered from the n/2+1 bins it keeps, as for IRFFT), and data is the spectrum laid out as RFFTN produces it, that shape with the last length replaced by n/2+1. The complex inverse runs along every axis but the last, then the real inverse along the last; the result is normalized by the product of the shape. This is numpy.fft.irfftn(data, s=shape).
data is read up to the spectrum's size and missing bins are zero, as for IRFFT2. shape must hold at least one axis and every length must be positive; IRFFTN panics otherwise. The input is not modified. The output has the product of shape values whatever the spectrum's length: bound the shape when it comes from untrusted input (see SECURITY.md).
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundR(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = round(v)
}
return out
}
func main() {
x := []float64{1, 2, 3, 4, 5, 6}
// The shape is the real output's: its last length cannot be recovered
// from the bins alone.
back := fft.IRFFTN(fft.RFFTN(x, []int{2, 3}), []int{2, 3})
fmt.Println(roundR(back))
}
Output: [1 2 3 4 5 6]
func IRFFTN32 ¶ added in v0.9.0
IRFFTN32 inverts RFFTN32, as IRFFTN inverts RFFTN: shape is the REAL output's, and the result is normalized by its product. The output has the product of shape values whatever the spectrum's length: bound the shape when it comes from untrusted input (see SECURITY.md).
func IRFFTN32With ¶ added in v0.9.0
IRFFTN32With is IRFFTN32 with numpy.fft.irfftn's axes and norm arguments, as IRFFTNWith: the real inverse runs along the LAST axis in o.Axes, the complex inverse along the others. o.Axes must name at least one axis; o.N must be zero.
func IRFFTNWith ¶ added in v0.4.0
func IRFFTNWith(data []complex128, shape []int, o Options) []float64
IRFFTNWith is IRFFTN with numpy.fft.irfftn's axes and norm arguments: the real inverse runs along the LAST axis in o.Axes (every axis when nil), whose spectrum holds shape[axis]/2+1 bins, the complex inverse along the others, and the result is scaled as o.Norm says. o.Axes must name at least one axis; o.N must be zero.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundR(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = round(v)
}
return out
}
func main() {
x := []float64{1, 2, 3, 4, 5, 6}
o := fft.Options{Axes: []int{0}, Norm: fft.NormOrtho}
fmt.Println(roundR(fft.IRFFTNWith(fft.RFFTNWith(x, []int{3, 2}, o), []int{3, 2}, o)))
}
Output: [1 2 3 4 5 6]
func IRFFTWith ¶ added in v0.4.0
func IRFFTWith(spectrum []complex128, o Options) []float64
IRFFTWith is IRFFT with numpy.fft.irfft's n and norm arguments. o.N is the length of the real output; zero selects numpy's default 2*(len(spectrum)-1), which reconstructs an even-length signal (pass the length explicitly for an odd one: n and n-1 keep the same number of bins). The spectrum is read up to o.N/2+1 bins and missing bins are zero, as for IRFFT; the imaginary parts of the zero-frequency bin and, for an even length, of the Nyquist bin are ignored, as numpy does. The result is scaled as o.Norm says (1/n under the default NormBackward). A length of zero (a spectrum of fewer than two bins and o.N zero) gives an empty result, where numpy raises. The input is not modified. o.Axes must be nil.
The output length is the caller's o.N whatever the spectrum's length: bound it when it comes from untrusted input (see SECURITY.md).
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundR(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = round(v)
}
return out
}
func main() {
spectrum := []complex128{6, -2 - 2i, 2}
// N = 0 takes numpy's default length 2*(3-1) = 4.
fmt.Println(roundR(fft.IRFFTWith(spectrum, fft.Options{})))
}
Output: [1 2 3 0]
func NextFastLen ¶ added in v0.4.0
NextFastLen returns the smallest length >= target that this package transforms fast, the counterpart of scipy.fft.next_fast_len(target, real) (https://docs.scipy.org/doc/scipy/reference/generated/scipy.fft.next_fast_len.html): zero-pad a signal to it before transforming (FFTWith/RFFTWith with Options{N: NextFastLen(len(x), ...)}).
What is fast depends on the library, so the rule differs from scipy's:
- complex (real == false): the 7-smooth lengths, 2^a·3^b·5^c·7^d. Every such length runs entirely on the Stockham engine's specialized radix 2/3/4/5/7/8 passes. A factor 11 or 13 also stays on the mixed-radix path but through its general O(p²) radix pass, and a larger prime factor goes to Rader or Bluestein. Measured on Apple M4 Max (2026-10-05, ns per point): 1001 = 7·11·13 cost 20 and 1100 = 2²·5²·11 cost 11, against 2.5 for 1008 and 1120; 2197 = 13³ cost 33 and 4067 = 7²·83 (Bluestein) 15, against 2.7 for 4096. scipy, whose pocketfft has specialized radix-11 passes, accepts 11-smooth lengths here.
- real (real == true): the EVEN 7-smooth lengths. An even length packs into a half-length complex transform; an odd one runs the full complex transform: as a real transform 1125 = 3²·5³ cost 4.7 ns per point against 1.6 for 1134 = 2·3⁴·7. scipy's real rule is 5-smooth, odd lengths included.
Targets 0 and 1 are returned unchanged (such transforms are trivial). A negative target panics, as does a target above the largest qualifying length that fits in an int.
Example ¶
package main
import (
"fmt"
"github.com/go-fft/fft"
)
func main() {
fmt.Println(fft.NextFastLen(1009, false)) // 1009 is prime; the next 7-smooth length is 1024
fmt.Println(fft.NextFastLen(1001, true)) // 1001 = 7·11·13 is not; 1008 = 2⁴·3²·7 is even and 7-smooth
}
Output: 1024 1008
func PSD ¶
PSD returns the one-sided power spectral density (periodogram) of the real-valued signal x sampled at spacing d, using the non-redundant RFFT bins. The result has length len(x)/2+1.
Each bin is scaled to a density: |X[k]|² / (fs·N) where fs = 1/d is the sampling rate and N = len(x). To conserve total power, every bin except DC (and the Nyquist bin for even N) is doubled to fold in the discarded mirror half. This matches scipy.signal.periodogram(x, fs, window="boxcar", scaling="density", return_onesided=True). The companion frequency axis is RFFTFreq(len(x), d). The input is not modified; an empty x returns an empty (non-nil) slice.
func RFFT ¶
func RFFT(x []float64) []complex128
RFFT returns the forward discrete Fourier transform of a real-valued signal, keeping only the non-redundant spectrum. For input of length N the result has length N/2+1 (integer division): bins 0..N/2. The discarded upper half is the conjugate mirror of the lower half (X[N-k] = conj(X[k])), so it carries no new information. This matches numpy.fft.rfft.
The transform is unnormalized, consistent with FFT:
X[k] = sum_{n=0}^{N-1} x[n] * exp(-2πi·k·n/N), k = 0 .. N/2.
For even N the real signal is packed into an N/2-point complex transform and untangled — about twice as fast as a full complex FFT — using twiddle tables cached per length. The input is not modified. Empty input returns an empty (non-nil) slice.
func RFFT2 ¶
func RFFT2(data []float64, shape [2]int) []complex128
RFFT2 returns the forward 2-D DFT of a real row-major matrix of the given shape (shape[0] rows × shape[1] columns). The real transform is applied along the last axis, so each output row keeps shape[1]/2+1 non-redundant bins; the result is a row-major matrix of shape shape[0]×(shape[1]/2+1). The full complex transform is then applied down the columns. This matches numpy.fft.rfft2.
shape lengths must be positive and shape[0]*shape[1] must equal len(data); RFFT2 panics otherwise. The input is not modified.
func RFFT2With ¶ added in v0.4.0
func RFFT2With(data []float64, shape [2]int, o Options) []complex128
RFFT2With is RFFT2 with numpy.fft.rfft2's axes and norm arguments. With o.Axes nil it runs RFFT2's plan and scales the result; with axes it is RFFTNWith on a two-axis shape.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
img := []float64{1, 1, 1, 1}
fmt.Println(roundC(fft.RFFT2With(img, [2]int{2, 2}, fft.Options{Norm: fft.NormForward})))
}
Output: [(1+0i) (0+0i) (0+0i) (0+0i)]
func RFFT2_32 ¶ added in v0.9.0
RFFT2_32 is RFFT2 in single precision: the forward 2-D DFT of a real row-major float32 matrix of shape shape[0]×shape[1], keeping shape[1]/2+1 bins per row (scipy.fft.rfft2 on float32 input). The same shape rules as RFFT2 apply; the input is not modified.
func RFFT2_32With ¶ added in v0.9.0
RFFT2_32With is RFFT2_32 with numpy.fft.rfft2's axes and norm arguments. With o.Axes nil it runs RFFT2_32's plan; with axes it is RFFTN32With on a two-axis shape.
func RFFT32 ¶ added in v0.6.0
RFFT32 returns the N/2+1 non-redundant bins of the real signal x in single precision, unnormalized like RFFT. Empty input returns an empty (non-nil) slice. Plans are cached per length.
Example ¶
RFFT32 keeps the N/2+1 non-redundant bins of a float32 signal; IRFFT32 needs the length back, since N and N+1 give as many bins.
package main
import (
"fmt"
"github.com/go-fft/fft"
)
// tidy turns the zeros of v positive for printing: whether an exactly
// cancelling sum comes out +0 or -0 depends on the CPU's fused multiply-add
// (loong64 and amd64 differ), and the sign of zero carries no information here.
func tidy(v []complex64) []complex64 {
out := make([]complex64, len(v))
for i, z := range v {
out[i] = complex(real(z)+0, imag(z)+0)
}
return out
}
func main() {
x := []float32{1, 2, 3, 4}
X := fft.RFFT32(x)
fmt.Println(tidy(X))
fmt.Println(fft.IRFFT32(X, len(x)))
}
Output: [(10+0i) (-2+2i) (-2+0i)] [1 2 3 4]
func RFFT32With ¶ added in v0.9.0
RFFT32With is RFFT32 with numpy.fft.rfft's n and norm arguments, as RFFTWith: the result holds n/2+1 bins of the input truncated or zero-padded to n = o.N points (len(x) when o.N is zero). o.Axes must be nil.
func RFFTFreq ¶
RFFTFreq returns the n/2+1 sample frequencies of a real FFT (RFFT) of input length n, given the sample spacing d. The result matches numpy.fft.rfftfreq(n, d) exactly:
f = [0, 1, ..., n//2] / (d·n), length n//2+1.
All frequencies are non-negative because RFFT keeps only the non-redundant lower half of the spectrum. n <= 0 returns an empty (non-nil) slice.
func RFFTN ¶ added in v0.4.0
func RFFTN(data []float64, shape []int) []complex128
RFFTN returns the forward N-dimensional DFT of the real row-major array data of the given shape, keeping only the non-redundant half of the last axis: the result is a row-major array of the same shape except that the last length n becomes n/2+1. The real transform runs along the last axis and the complex one along the others, unnormalized. This is numpy.fft.rfftn; RFFT2 is its two-dimensional case.
shape must hold at least one axis, every length must be positive and their product must equal len(data); RFFTN panics otherwise. The input is not modified.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
// A 2×2×4 real array: the last axis keeps 4/2+1 = 3 bins.
x := make([]float64, 16)
for i := range x {
x[i] = 1
}
s := fft.RFFTN(x, []int{2, 2, 4})
fmt.Println(len(s), roundC(s[:3]))
}
Output: 12 [(16+0i) (0+0i) (0+0i)]
func RFFTN32 ¶ added in v0.9.0
RFFTN32 is RFFTN in single precision: the forward N-dimensional DFT of the real row-major float32 array data, the real transform along the last axis (which keeps n/2+1 bins) and the complex one along the others (scipy.fft.rfftn on float32 input). The same rules as RFFTN apply.
func RFFTN32With ¶ added in v0.9.0
RFFTN32With is RFFTN32 with numpy.fft.rfftn's axes and norm arguments, as RFFTNWith: the real transform runs along the LAST axis listed. o.Axes must name at least one axis; o.N must be zero.
Example ¶
Batched real transforms: every row of a matrix of float32 signals, one plan, with Options.Axes as numpy's axis=-1.
rows := []float32{
1, 1, 1, 1,
1, 0, -1, 0,
}
S := fft.RFFTN32With(rows, []int{2, 4}, fft.Options{Axes: []int{-1}})
fmt.Println(tidy(S))
Output: [(4+0i) (0+0i) (0+0i) (0+0i) (2+0i) (0+0i)]
func RFFTNWith ¶ added in v0.4.0
func RFFTNWith(data []float64, shape []int, o Options) []complex128
RFFTNWith is RFFTN with numpy.fft.rfftn's axes and norm arguments: only the axes in o.Axes are transformed (every axis when nil), the real transform runs along the LAST axis listed — that axis of the output keeps n/2+1 bins — and the result is scaled as o.Norm says. o.Axes must name at least one axis; o.N must be zero.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
x := []float64{
1, 2,
3, 4,
5, 6,
}
// The real transform along axis 0 (the last axis listed): 3 rows keep
// 3/2+1 = 2 bins, and the output is 2×2.
fmt.Println(roundC(fft.RFFTNWith(x, []int{3, 2}, fft.Options{Axes: []int{0}})))
}
Output: [(9+0i) (12+0i) (-3+1.7321i) (-3+1.7321i)]
func RFFTWith ¶ added in v0.4.0
func RFFTWith(x []float64, o Options) []complex128
RFFTWith is RFFT with numpy.fft.rfft's n and norm arguments: the real input is truncated or zero-padded to o.N points (len(x) when o.N is zero), the result holds o.N/2+1 bins, and the transform is scaled as o.Norm says. RFFTWith(x, Options{}) equals RFFT(x). The input is not modified. o.Axes must be nil.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
r := []float64{1, 2, 3}
// Zero-pad to 4 points: 4/2+1 = 3 bins.
fmt.Println(roundC(fft.RFFTWith(r, fft.Options{N: 4})))
}
Output: [(6+0i) (-2-2i) (2+0i)]
func Spectrogram ¶
Spectrogram computes a sequence of one-sided power spectra over successive, optionally overlapping segments of the real signal x, the building block of a time–frequency display. segment is the segment length (window size) and overlap is the number of samples shared between consecutive segments (0 <= overlap < segment). Each segment is multiplied by window (which must have length segment) before its PSD is taken.
The return value is a slice of frames, each a []float64 of length segment/2+1 (the RFFTFreq(segment, d) axis); frame t covers samples [t·step, t·step+segment) with step = segment-overlap. Segments are taken only while a full window fits, so trailing samples shorter than segment are dropped (the common STFT convention). The input is not modified.
Spectrogram panics if segment <= 0, len(window) != segment, or overlap is out of range, mirroring the contract of scipy.signal.spectrogram.
Types ¶
type DCTPlan ¶ added in v0.5.0
type DCTPlan struct {
// contains filtered or unexported fields
}
A DCTPlan is a reusable discrete cosine transform of a fixed length and type (1 to 4), matching scipy.fft.dct and scipy.fft.idct. Like Plan it precomputes every twiddle factor once; its methods write into a caller-supplied destination. A DCTPlan is immutable and safe for concurrent use.
func NewDCTPlan ¶ added in v0.5.0
NewDCTPlan returns a plan for the DCT of type typ (1, 2, 3 or 4) of length n. It panics if typ is not 1..4 or if n is below the type's minimum: 2 for DCT-I, 1 for the others.
Example ¶
A plan computes repeated transforms of one length without allocating; dst may be src itself.
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round4 rounds to 4 decimals and turns the rounding residue of an exact zero
// (which may print as -0.0000 on one architecture and 0.0000 on another) into 0.
func round4(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = math.Round(v*1e4) / 1e4
if out[i] == 0 {
out[i] = 0
}
}
return out
}
func main() {
p := fft.NewDCTPlan(4, 4)
buf := []float64{1, 0, 0, 0}
p.DCT(buf, buf, fft.NormBackward)
fmt.Println(round4(buf))
p.IDCT(buf, buf, fft.NormBackward)
fmt.Println(round4(buf))
}
Output: [1.9616 1.6629 1.1111 0.3902] [1 0 0 0]
func (*DCTPlan) DCT ¶ added in v0.5.0
DCT writes the DCT of src into dst and returns dst[:Len()], as scipy.fft.dct(src, type=Type(), norm=norm). dst and src must have at least Len() elements; dst may alias src. src is not modified unless it aliases dst.
func (*DCTPlan) IDCT ¶ added in v0.5.0
IDCT writes the inverse DCT of src into dst and returns dst[:Len()], as scipy.fft.idct(src, type=Type(), norm=norm): IDCT(DCT(x, norm), norm) == x for every norm. The same slice rules as DCT apply.
type DCTPlan32 ¶ added in v0.9.0
type DCTPlan32 struct {
// contains filtered or unexported fields
}
A DCTPlan32 is the single-precision counterpart of DCTPlan: a reusable DCT of a fixed length and type (1 to 4) over float32 data, matching scipy.fft.dct and scipy.fft.idct on float32 input. It is immutable and safe for concurrent use.
func NewDCTPlan32 ¶ added in v0.9.0
NewDCTPlan32 returns a single-precision plan for the DCT of type typ (1, 2, 3 or 4) of length n. It panics if typ is not 1..4 or if n is below the type's minimum: 2 for DCT-I, 1 for the others.
func (*DCTPlan32) DCT ¶ added in v0.9.0
DCT writes the DCT of src into dst and returns dst[:Len()], as scipy.fft.dct(src, type=Type(), norm=norm) on float32 input. dst and src must have at least Len() elements; dst may alias src.
func (*DCTPlan32) IDCT ¶ added in v0.9.0
IDCT writes the inverse DCT of src into dst and returns dst[:Len()], as scipy.fft.idct(src, type=Type(), norm=norm). The same slice rules as DCT apply.
type DSTPlan ¶ added in v0.5.0
type DSTPlan struct {
// contains filtered or unexported fields
}
A DSTPlan is a reusable discrete sine transform of a fixed length and type (1 to 4), matching scipy.fft.dst and scipy.fft.idst. It is immutable and safe for concurrent use.
func NewDSTPlan ¶ added in v0.5.0
NewDSTPlan returns a plan for the DST of type typ (1, 2, 3 or 4) of length n >= 1. It panics if typ is not 1..4 or n < 1.
func (*DSTPlan) DST ¶ added in v0.5.0
DST writes the DST of src into dst and returns dst[:Len()], as scipy.fft.dst(src, type=Type(), norm=norm). dst and src must have at least Len() elements; dst may alias src. src is not modified unless it aliases dst.
func (*DSTPlan) IDST ¶ added in v0.5.0
IDST writes the inverse DST of src into dst and returns dst[:Len()], as scipy.fft.idst(src, type=Type(), norm=norm): IDST(DST(x, norm), norm) == x for every norm. The same slice rules as DST apply.
type DSTPlan32 ¶ added in v0.9.0
type DSTPlan32 struct {
// contains filtered or unexported fields
}
A DSTPlan32 is the single-precision counterpart of DSTPlan, matching scipy.fft.dst and scipy.fft.idst on float32 input. It is immutable and safe for concurrent use.
func NewDSTPlan32 ¶ added in v0.9.0
NewDSTPlan32 returns a single-precision plan for the DST of type typ (1, 2, 3 or 4) of length n >= 1. It panics if typ is not 1..4 or n < 1.
func (*DSTPlan32) DST ¶ added in v0.9.0
DST writes the DST of src into dst and returns dst[:Len()], as scipy.fft.dst(src, type=Type(), norm=norm) on float32 input. dst and src must have at least Len() elements; dst may alias src.
func (*DSTPlan32) IDST ¶ added in v0.9.0
IDST writes the inverse DST of src into dst and returns dst[:Len()], as scipy.fft.idst(src, type=Type(), norm=norm). The same slice rules as DST apply.
type Norm ¶ added in v0.3.0
type Norm int
Norm selects how a transform pair is scaled, as numpy.fft's and scipy.fft's norm argument does. The zero value is NormBackward, numpy's default and what FFT/IFFT do: the forward transform is unscaled and the inverse divides by n.
const ( // NormBackward leaves the forward transform unscaled and scales the // inverse by 1/n (numpy norm="backward", the default). NormBackward Norm = iota // NormOrtho scales both directions by 1/sqrt(n), which makes the // transform unitary (numpy norm="ortho"). NormOrtho // NormForward scales the forward transform by 1/n and leaves the inverse // unscaled (numpy norm="forward"). NormForward )
type Options ¶ added in v0.4.0
type Options struct {
// N is numpy's n: the number of input points a 1-D transform uses. The
// input is truncated to N points, or zero-padded to N, before the
// transform. For IRFFTWith and HFFTWith, N is the length of the real
// output (numpy's default for both being 2*(len(input)-1)). Zero selects
// numpy's default; a negative N panics. N must be zero for the
// multi-dimensional transforms.
N int
// Norm is numpy's norm: how the forward/inverse pair is scaled. The zero
// value, NormBackward, is numpy's default and what FFT/IFFT do.
Norm Norm
// Axes is numpy's axes: the axes of a row-major array the
// multi-dimensional transforms run along. Negative values count from the
// last axis, as in numpy (-1 is the last axis). nil transforms every axis;
// an empty non-nil slice transforms none. An axis may not appear twice.
// For RFFTNWith/IRFFTNWith the real transform runs along the LAST axis
// listed, as numpy.fft.rfftn does. Axes must be nil for the 1-D
// transforms.
Axes []int
// FMA lets the transform fuse its twiddle products with fused
// multiply-add instructions, which is faster and, measured against
// numpy.fft, as accurate (see "Fused multiply-add" in the package
// documentation), but NOT bit-identical to the default: the results
// differ from FFT's in the last bits. The default (false) keeps every
// amd64 kernel bit-identical to the package's Go reference. FMA is a
// request: it takes effect on amd64 CPUs with FMA3, and elsewhere the
// transform is the default one, bit for bit. The float32 transforms
// ignore it. NewPlanWith, NewRealPlanWith, NewPlanNWith and
// NewRealPlan2With take it for plans.
FMA bool
}
Options carries numpy.fft's optional keyword arguments — n, norm and axes — to the ...With variants of the transforms (FFTWith, RFFTNWith, ...). Its zero value is numpy's defaults, so Options{} makes every ...With function behave exactly like its plain counterpart, and a call names only what it changes:
fft.FFTWith(x, fft.Options{N: 1024, Norm: fft.NormOrtho})
fft.FFTNWith(img, []int{rows, cols}, fft.Options{Axes: []int{-1}})
A field that has no meaning for the transform it is passed to is refused with a panic rather than silently ignored: N belongs to the 1-D transforms, Axes to the multi-dimensional ones.
A struct was chosen over functional options or extra positional arguments because it keeps the existing signatures untouched (adding a variadic parameter to FFT would break every func-typed use of it), because its zero value already is numpy's default for each field (the zero Norm is NormBackward), and because it costs nothing at run time: no closures, no allocation, one type to learn for every transform.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
x := []complex128{1, 2, 3, 4}
// The zero Options is numpy's defaults: the same as FFT.
fmt.Println(roundC(fft.FFTWith(x, fft.Options{})))
// Name only what changes: pad to 8 points, unitary scaling.
fmt.Println(len(fft.FFTWith(x, fft.Options{N: 8, Norm: fft.NormOrtho})))
}
Output: [(10+0i) (-2+2i) (-2+0i) (-2-2i)] 8
type Plan ¶
type Plan struct {
// contains filtered or unexported fields
}
A Plan is a reusable, precomputed transform of a fixed length N. Building a plan factors N and precomputes every twiddle factor once; the resulting tables are then amortized across an unbounded number of FFT/IFFT calls, so repeated transforms of the same length pay no sin/cos cost. Plans are immutable after construction and safe for concurrent use by multiple goroutines (the transform methods write only into the caller-supplied destination and per-call scratch).
For one-off transforms the package-level FFT/IFFT functions are more convenient; they consult an internal plan cache so even they avoid recomputing twiddles for a length they have seen before.
func NewPlan ¶
NewPlan returns a transform plan for length n, precomputing all twiddle factors. n may be any non-negative integer; n == 0 and n == 1 produce a trivial plan. The same plan serves both the forward FFT and the inverse IFFT.
func NewPlanWith ¶ added in v0.28.0
NewPlanWith is NewPlan with options: o.FMA asks for an FMA plan (see Options.FMA), which is built where the CPU has FMA3 and is otherwise the plan NewPlan builds. The other fields of Options have no meaning for a plan and must be zero: the length is n, and the plan's methods take a Norm each (FFTNorm, IFFTNorm). NewPlanWith(n, Options{}) is NewPlan(n).
func (*Plan) FFT ¶
func (p *Plan) FFT(dst, src []complex128) []complex128
FFT writes the forward DFT of src into dst and returns dst. dst and src must each have length Len(); dst may alias src. src is not modified unless it aliases dst.
func (*Plan) FFTNorm ¶ added in v0.4.0
func (p *Plan) FFTNorm(dst, src []complex128, m Norm) []complex128
FFTNorm is FFT scaled as m says: unscaled under NormBackward, 1/sqrt(n) under NormOrtho, 1/n under NormForward. dst and src follow FFT's rules.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
p := fft.NewPlan(4)
dst := make([]complex128, 4)
fmt.Println(roundC(p.FFTNorm(dst, []complex128{1, 1, 1, 1}, fft.NormForward)))
}
Output: [(1+0i) (0+0i) (0+0i) (0+0i)]
func (*Plan) IFFT ¶
func (p *Plan) IFFT(dst, src []complex128) []complex128
IFFT writes the inverse DFT of src into dst (normalized by N) and returns dst. dst and src must each have length Len(); dst may alias src.
func (*Plan) IFFTNorm ¶ added in v0.4.0
func (p *Plan) IFFTNorm(dst, src []complex128, m Norm) []complex128
IFFTNorm is IFFT scaled as m says: 1/n under NormBackward (as IFFT), 1/sqrt(n) under NormOrtho, unscaled under NormForward. dst and src follow IFFT's rules.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
p := fft.NewPlan(4)
dst := make([]complex128, 4)
fmt.Println(roundC(p.IFFTNorm(dst, []complex128{1, 0, 0, 0}, fft.NormForward)))
}
Output: [(1+0i) (1+0i) (1+0i) (1+0i)]
type Plan32 ¶ added in v0.6.0
type Plan32 struct {
// contains filtered or unexported fields
}
A Plan32 is the single-precision counterpart of Plan: a reusable transform of a fixed length N over complex64 data, as scipy.fft computes when it is given complex64 input (and numpy.fft since NumPy 2.0). Every length is accepted and routed as Plan routes it: smooth lengths (prime factors <= 13) to the Stockham passes, a prime whose N-1 is 7-smooth to Rader's algorithm, anything else to Bluestein's chirp-z.
Precision. The arithmetic is float32 throughout, as in FFTW's fftwf_ and pocketfft's float instantiation, but every precomputed table — twiddles, Rader's and Bluestein's kernel spectra, Bluestein's chirp — is computed in float64 by the double-precision engine and rounded once to float32. A table built in float32 (or by a float32 sin/cos recurrence) would carry its own O(eps32·log N) error into every transform; rounded once, each entry is within half an ulp. The error of a transform is then O(eps32·log2 N) relative to the vector's 2-norm; the tests hold it to eps32·log2 N against the DFT of the same input computed in float64, for every length up to 130 and for powers of two up to 2^20, composites and primes beyond. The worst error measured is 0.49 of that bound (N = 2, NormOrtho), 0.14 from 1024 points up.
The engines are separate float32 code, not a generic instantiation of the float64 ones, because a generic engine measured slower on the float64 path. Go does not let real, imag or complex take a type-parameter argument (go.dev/issue/50937), so a generic butterfly has to reach the parts through a conversion to complex128 — free for T = complex128 in itself, but it raises the inliner's cost of the butterflies (bfly4 from 56 to 88, bfly3 from 69 to 175, over the budget of 80), they stop being inlined into the pass loops, and the float64 transforms got 1.44× slower (geometric mean of the Complex/Real/CReal benchmarks, interleaved A/B, Apple M4 Max). The float64 path also dispatches to amd64 assembly through internal/kernels, which a complex64 instantiation would have to bypass anyway.
Plans are immutable after construction and safe for concurrent use.
func NewPlan32 ¶ added in v0.6.0
NewPlan32 returns a single-precision transform plan for length n, precomputing all twiddle factors. n may be any non-negative integer; n == 0 and n == 1 produce a trivial plan.
func (*Plan32) FFT ¶ added in v0.6.0
FFT writes the forward DFT of src into dst, unnormalized, and returns dst. dst and src must each have at least Len() elements; dst may alias src.
func (*Plan32) FFTNorm ¶ added in v0.6.0
FFTNorm writes the forward DFT of src into dst, scaled as norm says (1 for NormBackward, 1/sqrt(N) for NormOrtho, 1/N for NormForward), and returns dst. It panics on a Norm that is not one of the three constants.
Example ¶
A Plan32 is reused across transforms of one length, here with the unitary scaling (numpy's norm="ortho"): both directions divide by sqrt(N).
package main
import (
"fmt"
"github.com/go-fft/fft"
)
// tidy turns the zeros of v positive for printing: whether an exactly
// cancelling sum comes out +0 or -0 depends on the CPU's fused multiply-add
// (loong64 and amd64 differ), and the sign of zero carries no information here.
func tidy(v []complex64) []complex64 {
out := make([]complex64, len(v))
for i, z := range v {
out[i] = complex(real(z)+0, imag(z)+0)
}
return out
}
func main() {
p := fft.NewPlan32(4)
x := []complex64{1, 1, 1, 1}
X := p.FFTNorm(make([]complex64, 4), x, fft.NormOrtho)
fmt.Println(tidy(X))
fmt.Println(tidy(p.IFFTNorm(make([]complex64, 4), X, fft.NormOrtho)))
}
Output: [(2+0i) (0+0i) (0+0i) (0+0i)] [(1+0i) (1+0i) (1+0i) (1+0i)]
func (*Plan32) IFFT ¶ added in v0.6.0
IFFT writes the inverse DFT of src into dst, normalized by N, and returns dst. dst and src must each have at least Len() elements; dst may alias src.
type PlanN ¶
type PlanN struct {
// contains filtered or unexported fields
}
A PlanN is a reusable N-dimensional complex transform of a fixed row-major (C-order) shape: the N-D counterpart of Plan, the way FFTW's fftw_plan_dft(rank, dims, …) is the counterpart of its 1-D plans. Building it resolves one 1-D plan per axis; FFT and IFFT then write into a caller-supplied slice and, in steady state, allocate nothing — unlike FFTN/FFT2, which return a new slice each call. On a many-core host that allocation is what dominates a small repeated transform: a 128×128 FFT2 spent about three quarters of its time in the garbage collector on a 128-thread machine (see BENCHMARKS.md).
PlanN is immutable after construction and safe for concurrent use; each call borrows private scratch from a pool.
func NewPlanN ¶
NewPlanN returns a plan for arrays of the given row-major shape. Every length must be positive; NewPlanN panics otherwise. An empty shape is the single-element (scalar) array.
func NewPlanNWith ¶ added in v0.28.0
NewPlanNWith is NewPlanN with options: o.FMA asks for an FMA plan (see Options.FMA), whose every axis, the ones transformed as strips of batched passes included, runs on FMA plans. The other fields must be zero, as for NewPlanWith. NewPlanNWith(shape, Options{}) is NewPlanN(shape...).
func (*PlanN) FFT ¶
func (p *PlanN) FFT(dst, src []complex128) []complex128
FFT writes the forward N-dimensional DFT of src into dst and returns dst. dst and src must each have length Len(); dst may alias src. It matches FFTN.
func (*PlanN) FFTNorm ¶ added in v0.4.0
func (p *PlanN) FFTNorm(dst, src []complex128, m Norm) []complex128
FFTNorm is FFT scaled as m says, n being Len(), the product of the shape (see Plan.FFTNorm).
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
p := fft.NewPlanN(2, 2)
dst := make([]complex128, 4)
fmt.Println(roundC(p.FFTNorm(dst, []complex128{1, 1, 1, 1}, fft.NormOrtho)))
}
Output: [(2+0i) (0+0i) (0+0i) (0+0i)]
func (*PlanN) IFFT ¶
func (p *PlanN) IFFT(dst, src []complex128) []complex128
IFFT writes the inverse N-dimensional DFT of src into dst, normalized by Len(), and returns dst. dst may alias src. It matches IFFTN.
func (*PlanN) IFFTNorm ¶ added in v0.4.0
func (p *PlanN) IFFTNorm(dst, src []complex128, m Norm) []complex128
IFFTNorm is IFFT scaled as m says, n being Len(), the product of the shape (see Plan.IFFTNorm).
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
p := fft.NewPlanN(2, 2)
dst := make([]complex128, 4)
fmt.Println(roundC(p.IFFTNorm(dst, []complex128{2, 0, 0, 0}, fft.NormOrtho)))
}
Output: [(1+0i) (1+0i) (1+0i) (1+0i)]
type PlanN32 ¶ added in v0.9.0
type PlanN32 struct {
// contains filtered or unexported fields
}
A PlanN32 is the single-precision counterpart of PlanN: a reusable N-dimensional complex64 transform of a fixed row-major (C-order) shape, as scipy.fft.fftn computes for complex64 input. It runs a Plan32 along each axis; FFT and IFFT write into a caller-supplied slice. PlanN32 is immutable after construction and safe for concurrent use.
Example ¶
A PlanN32 serves repeated transforms of one shape, writing into the caller's slice.
p := fft.NewPlanN32(2, 3)
x := []complex64{1, 1, 1, 1, 1, 1}
X := p.FFTNorm(make([]complex64, p.Len()), x, fft.NormOrtho)
fmt.Println(round4f32([]float32{real(X[0])}), tidy(X[1:]))
Output: [2.4495] [(0+0i) (0+0i) (0+0i) (0+0i) (0+0i)]
func NewPlanN32 ¶ added in v0.9.0
NewPlanN32 returns a single-precision plan for arrays of the given row-major shape. Every length must be positive; NewPlanN32 panics otherwise. An empty shape is the single-element (scalar) array.
func (*PlanN32) FFT ¶ added in v0.9.0
FFT writes the forward N-dimensional DFT of src into dst, unnormalized, and returns dst. dst and src must each have length Len(); dst may alias src. It matches FFTN32.
func (*PlanN32) FFTNorm ¶ added in v0.9.0
FFTNorm is FFT scaled as m says, n being Len(): unscaled under NormBackward, 1/sqrt(n) under NormOrtho, 1/n under NormForward.
func (*PlanN32) IFFT ¶ added in v0.9.0
IFFT writes the inverse N-dimensional DFT of src into dst, normalized by Len(), and returns dst. dst may alias src. It matches IFFTN32.
func (*PlanN32) IFFTNorm ¶ added in v0.9.0
IFFTNorm is IFFT scaled as m says, n being Len(): 1/n under NormBackward (as IFFT), 1/sqrt(n) under NormOrtho, unscaled under NormForward.
type RealPlan ¶
type RealPlan struct {
// contains filtered or unexported fields
}
A RealPlan is a reusable, precomputed real-input transform of a fixed length N. Like Plan it amortizes all twiddle computation across calls; it is the real-signal counterpart used by RFFT/IRFFT. RealPlans are immutable after construction and safe for concurrent use.
For even N the plan packs the N real samples into an N/2-point complex transform and untangles the result with a precomputed table — about twice as fast as a full complex FFT. For odd N (which cannot be packed) it wraps a full complex plan of length N.
func NewRealPlan ¶
NewRealPlan returns a real-input transform plan for length n, precomputing all twiddle factors. n must be non-negative.
func NewRealPlanWith ¶ added in v0.28.0
NewRealPlanWith is NewRealPlan with options: o.FMA asks for an FMA plan (see Options.FMA), whose complex half (or, for an odd n, full) transform is an FMA plan; the untangle is the default one. The other fields must be zero, as for NewPlanWith. NewRealPlanWith(n, Options{}) is NewRealPlan(n).
func (*RealPlan) IRFFT ¶
func (p *RealPlan) IRFFT(dst []float64, src []complex128) []float64
IRFFT writes the real signal of length Len() reconstructed from the half spectrum src into dst and returns dst. dst must have length Len(); src is read up to min(len(src), Len()/2+1) bins. The result is normalized by N. src is not modified.
For even N the inverse mirrors the forward packing: the half spectrum is pre-processed into an N/2-point complex spectrum, run through one N/2-point inverse complex FFT, and unpacked — half the arithmetic and memory traffic of promoting to a full conjugate-symmetric length-N inverse transform. For odd N (and the trivial N<=1) it falls back to the full conjugate-mirror inverse.
func (*RealPlan) IRFFTNorm ¶ added in v0.4.0
func (p *RealPlan) IRFFTNorm(dst []float64, src []complex128, m Norm) []float64
IRFFTNorm is IRFFT scaled as m says (see Plan.IFFTNorm). dst and src follow IRFFT's rules.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundR(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = round(v)
}
return out
}
func main() {
p := fft.NewRealPlan(4)
dst := make([]float64, 4)
fmt.Println(roundR(p.IRFFTNorm(dst, []complex128{2, 0, 0}, fft.NormOrtho)))
}
Output: [1 1 1 1]
func (*RealPlan) RFFT ¶
func (p *RealPlan) RFFT(dst []complex128, src []float64) []complex128
RFFT writes the non-redundant N/2+1 spectral bins of the real signal src into dst and returns dst. src must have length Len(); dst must have length Len()/2+1. src is not modified. dst may share memory with src (which only an unsafe conversion can arrange): the transform then goes through a private buffer instead of building the half-length spectrum in dst.
func (*RealPlan) RFFTNorm ¶ added in v0.4.0
func (p *RealPlan) RFFTNorm(dst []complex128, src []float64, m Norm) []complex128
RFFTNorm is RFFT scaled as m says (see Plan.FFTNorm). dst and src follow RFFT's rules.
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
p := fft.NewRealPlan(4)
dst := make([]complex128, 3)
fmt.Println(roundC(p.RFFTNorm(dst, []float64{1, 1, 1, 1}, fft.NormOrtho)))
}
Output: [(2+0i) (0+0i) (0+0i)]
type RealPlan2 ¶
type RealPlan2 struct {
// contains filtered or unexported fields
}
A RealPlan2 is a reusable real 2-D transform of a fixed rows×cols shape: the plan behind RFFT2/IRFFT2, as PlanN is behind FFTN. Its RFFT and IRFFT write into caller-supplied slices, so a repeated transform of an even-width matrix allocates nothing in steady state (an odd width goes through the full complex row transform, which allocates). It is immutable after construction and safe for concurrent use.
func NewRealPlan2 ¶
NewRealPlan2 returns a plan for real rows×cols matrices. Both lengths must be positive; NewRealPlan2 panics otherwise.
func NewRealPlan2With ¶ added in v0.28.0
NewRealPlan2With is NewRealPlan2 with options: o.FMA asks for an FMA plan (see Options.FMA), whose row and column transforms are FMA plans. The other fields must be zero, as for NewPlanWith. NewRealPlan2With(rows, cols, Options{}) is NewRealPlan2(rows, cols).
func (*RealPlan2) IRFFT ¶
func (p *RealPlan2) IRFFT(dst []float64, src []complex128) []float64
IRFFT writes the real matrix (rows×cols) whose spectrum is src (SpectrumLen bins, the RFFT layout) into dst, normalized by rows×cols, and returns dst. It matches IRFFT2. src is not modified.
func (*RealPlan2) IRFFTNorm ¶ added in v0.4.0
func (p *RealPlan2) IRFFTNorm(dst []float64, src []complex128, m Norm) []float64
IRFFTNorm is IRFFT scaled as m says, n being rows×cols (see Plan.IFFTNorm).
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundR(x []float64) []float64 {
out := make([]float64, len(x))
for i, v := range x {
out[i] = round(v)
}
return out
}
func main() {
p := fft.NewRealPlan2(2, 2)
dst := make([]float64, 4)
fmt.Println(roundR(p.IRFFTNorm(dst, []complex128{1, 0, 0, 0}, fft.NormForward)))
}
Output: [1 1 1 1]
func (*RealPlan2) RFFT ¶
func (p *RealPlan2) RFFT(dst []complex128, src []float64) []complex128
RFFT writes the forward 2-D DFT of the real row-major matrix src (rows×cols) into dst (rows×(cols/2+1), SpectrumLen bins) and returns dst. It matches RFFT2. src is not modified.
func (*RealPlan2) RFFTNorm ¶ added in v0.4.0
func (p *RealPlan2) RFFTNorm(dst []complex128, src []float64, m Norm) []complex128
RFFTNorm is RFFT scaled as m says, n being rows×cols (see Plan.FFTNorm).
Example ¶
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
// round keeps four decimals and turns -0 into 0, so the examples print stable
// output across architectures.
func round(v float64) float64 {
r := math.Round(v*1e4) / 1e4
if r == 0 {
return 0
}
return r
}
func roundC(x []complex128) []complex128 {
out := make([]complex128, len(x))
for i, v := range x {
out[i] = complex(round(real(v)), round(imag(v)))
}
return out
}
func main() {
p := fft.NewRealPlan2(2, 2)
dst := make([]complex128, p.SpectrumLen())
fmt.Println(roundC(p.RFFTNorm(dst, []float64{1, 1, 1, 1}, fft.NormForward)))
}
Output: [(1+0i) (0+0i) (0+0i) (0+0i)]
func (*RealPlan2) SpectrumLen ¶
SpectrumLen is the number of bins RFFT writes and IRFFT reads: rows×(cols/2+1).
type RealPlan2_32 ¶ added in v0.9.0
type RealPlan2_32 struct {
// contains filtered or unexported fields
}
A RealPlan2_32 is the single-precision counterpart of RealPlan2: a reusable real 2-D transform of a fixed rows×cols shape over float32 samples and complex64 bins. It is immutable after construction and safe for concurrent use.
func NewRealPlan2_32 ¶ added in v0.9.0
func NewRealPlan2_32(rows, cols int) *RealPlan2_32
NewRealPlan2_32 returns a single-precision plan for real rows×cols matrices. Both lengths must be positive; NewRealPlan2_32 panics otherwise.
func (*RealPlan2_32) IRFFT ¶ added in v0.9.0
func (p *RealPlan2_32) IRFFT(dst []float32, src []complex64) []float32
IRFFT writes the real matrix (rows×cols) whose spectrum is src (SpectrumLen bins, the RFFT layout) into dst, normalized by rows×cols, and returns dst. It matches IRFFT2_32. src is not modified.
func (*RealPlan2_32) IRFFTNorm ¶ added in v0.9.0
func (p *RealPlan2_32) IRFFTNorm(dst []float32, src []complex64, m Norm) []float32
IRFFTNorm is IRFFT scaled as m says, n being rows×cols (see Plan32.IFFTNorm). The rows are inverted unscaled and the factor is applied once, rounded once to float32.
func (*RealPlan2_32) RFFT ¶ added in v0.9.0
func (p *RealPlan2_32) RFFT(dst []complex64, src []float32) []complex64
RFFT writes the forward 2-D DFT of the real row-major matrix src (rows×cols) into dst (rows×(cols/2+1), SpectrumLen bins), unnormalized, and returns dst. It matches RFFT2_32. src is not modified.
func (*RealPlan2_32) RFFTNorm ¶ added in v0.9.0
func (p *RealPlan2_32) RFFTNorm(dst []complex64, src []float32, m Norm) []complex64
RFFTNorm is RFFT scaled as m says, n being rows×cols (see Plan32.FFTNorm).
func (*RealPlan2_32) SpectrumLen ¶ added in v0.9.0
func (p *RealPlan2_32) SpectrumLen() int
SpectrumLen is the number of bins RFFT writes and IRFFT reads: rows×(cols/2+1).
type RealPlan32 ¶ added in v0.6.0
type RealPlan32 struct {
// contains filtered or unexported fields
}
A RealPlan32 is the single-precision counterpart of RealPlan: a reusable real-input transform of a fixed length N over float32 samples and complex64 bins. For even N the samples are packed into an N/2-point Plan32 and untangled with a table computed in float64 and rounded once; for odd N a full-length Plan32 is used. RealPlan32s are immutable after construction and safe for concurrent use.
Example ¶
A RealPlan32 serves repeated real transforms of one length.
package main
import (
"fmt"
"math"
"github.com/go-fft/fft"
)
func main() {
p := fft.NewRealPlan32(8)
x := []float32{0, 1, 0, -1, 0, 1, 0, -1} // two cycles of a sine
X := p.RFFT(make([]complex64, 5), x)
for k, v := range X {
fmt.Printf("bin %d: magnitude %.3f\n", k, math.Hypot(float64(real(v)), float64(imag(v))))
}
}
Output: bin 0: magnitude 0.000 bin 1: magnitude 0.000 bin 2: magnitude 4.000 bin 3: magnitude 0.000 bin 4: magnitude 0.000
func NewRealPlan32 ¶ added in v0.6.0
func NewRealPlan32(n int) *RealPlan32
NewRealPlan32 returns a single-precision real-input plan for length n (n >= 0).
func (*RealPlan32) IRFFT ¶ added in v0.6.0
func (p *RealPlan32) IRFFT(dst []float32, src []complex64) []float32
IRFFT writes the real signal of length Len() reconstructed from the half spectrum src into dst, normalized by N, and returns dst[:N]. src is read up to min(len(src), Len()/2+1) bins; missing bins count as zero, and the imaginary parts of the DC (and, for even N, Nyquist) bins are ignored. src is not modified.
func (*RealPlan32) IRFFTNorm ¶ added in v0.6.0
func (p *RealPlan32) IRFFTNorm(dst []float32, src []complex64, norm Norm) []float32
IRFFTNorm is IRFFT scaled as norm says (1/N, 1/sqrt(N) or 1). It panics on a Norm that is not one of the three constants.
func (*RealPlan32) Len ¶ added in v0.6.0
func (p *RealPlan32) Len() int
Len reports the real-input length the plan was built for.
func (*RealPlan32) RFFT ¶ added in v0.6.0
func (p *RealPlan32) RFFT(dst []complex64, src []float32) []complex64
RFFT writes the N/2+1 non-redundant bins of the real signal src into dst, unnormalized, and returns dst[:N/2+1]. src must have at least Len() elements and dst at least Len()/2+1. src is not modified.
Source Files
¶
- armreal_nd.go
- armreal_route_noarm64.go
- bluestein.go
- cascade.go
- comp_route_amd64.go
- dct.go
- dct32.go
- dctn.go
- doc.go
- dst.go
- fastlen.go
- fft.go
- fma.go
- fma_amd64.go
- freq.go
- iterative.go
- mixedradix.go
- ndfft.go
- norm.go
- options.go
- options1d.go
- options32.go
- optionsnd.go
- parallel.go
- plan.go
- plan32.go
- plann.go
- plann32.go
- planorm.go
- rader.go
- radix12.go
- radix16.go
- radix32.go
- radix5q.go
- radix9.go
- realplan.go
- realplan2.go
- realplan2_32.go
- realplan32.go
- rfft.go
- rfft2.go
- route_amd64.go
- shift.go
- split.go
- splitradix.go
- stockham.go
- stockham32_passes.go
- strip32.go
- window.go
- znstack.go
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
kernels
Package kernels holds the inner loops of the FFT — the bit-reversal permutation and the radix-2 butterfly stages — isolated from the public API.
|
Package kernels holds the inner loops of the FFT — the bit-reversal permutation and the radix-2 butterfly stages — isolated from the public API. |
