{
"title": "fftshift",
"category": "math/fft",
"keywords": [
"fftshift",
"fourier transform",
"frequency centering",
"spectrum",
"gpu"
],
"summary": "Shift zero-frequency components to the center of a spectrum.",
"references": [],
"gpu_support": {
"elementwise": false,
"reduction": false,
"precisions": [
"f32",
"f64"
],
"broadcasting": "none",
"notes": "Uses the provider circshift hook when available; otherwise gathers once, shifts on the host, and re-uploads."
},
"fusion": {
"elementwise": false,
"reduction": false,
"max_inputs": 1,
"constants": "inline"
},
"requires_feature": null,
"tested": {
"unit": "builtins::math::fft::fftshift::tests",
"integration": "builtins::math::fft::fftshift::tests::fftshift_gpu_roundtrip"
},
"description": "`fftshift(X)` circularly shifts the output of an FFT so that the zero-frequency component moves to the center of each transformed dimension. This makes spectra easier to inspect and aligns with MATLAB's plotting conventions.",
"behaviors": [
"When called without a dimension list, `fftshift` shifts along every dimension by `floor(size(X, dim) / 2)`.",
"`fftshift(X, dims)` shifts only the specified dimensions. `dims` can be a scalar, vector, or logical mask.",
"Dimensions of length 0 or 1 are left unchanged.",
"Inputs can be real or complex and may already reside on the GPU (`gpuArray`)."
],
"examples": [
{
"description": "Centering the spectrum of a 1-D FFT result with even length",
"input": "x = [0 1 2 3 4 5 6 7];\nfx = fft(x);\ny = fftshift(fx)",
"output": "y = [-4 -4-1.6569i -4-4i -4-9.6569i 28 -4+9.6569i -4+4i -4+1.6569i]"
},
{
"description": "Handling odd-length vectors",
"input": "x = 1:5;\ny = fftshift(x)",
"output": "y = [4 5 1 2 3]"
},
{
"description": "Centering both axes of a 2-D FFT",
"input": "A = [1 2 3; 4 5 6];\nC = fftshift(A)",
"output": "C =\n 6 4 5\n 3 1 2"
},
{
"description": "Shifting only one dimension of a matrix",
"input": "A = [1 2 3; 4 5 6];\nrowCentered = fftshift(A, 1) % shift rows only",
"output": "rowCentered =\n 4 5 6\n 1 2 3"
},
{
"description": "Applying `fftshift` to a gpuArray spectrum",
"input": "G = gpuArray(0:7);\ncentered = fftshift(G);\nH = gather(centered)",
"output": "H = [4 5 6 7 0 1 2 3]"
}
],
"faqs": [
{
"question": "When should I call `fftshift`?",
"answer": "Call `fftshift` whenever you need to center FFT outputs before visualising spectra, computing radial averages, or applying filters that expect zero frequency in the middle of the array."
},
{
"question": "Does `fftshift` modify the phase or magnitude of the FFT?",
"answer": "No. `fftshift` only reorders the samples. Magnitudes, phases, and the overall information content remain unchanged."
},
{
"question": "How do I undo `fftshift`?",
"answer": "Use `ifftshift`, which performs the inverse rearrangement. The sequence `ifftshift(fftshift(X))` returns `X` for all supported inputs."
},
{
"question": "Can I apply `fftshift` to only one dimension?",
"answer": "Yes. Pass a dimension index or vector, e.g. `fftshift(X, 2)` to shift column channels only."
},
{
"question": "Does `fftshift` work with gpuArray inputs?",
"answer": "Yes. RunMat keeps data on the GPU whenever the provider exposes the `circshift` hook, matching MATLAB's `gpuArray` behaviour."
},
{
"question": "How does `fftshift` handle empty inputs?",
"answer": "Empty arrays are returned unchanged with identical shape metadata."
},
{
"question": "Can I use `fftshift` on logical arrays?",
"answer": "Yes. Logical arrays are shifted without changing their logical element type."
}
],
"links": [
{
"label": "fft",
"url": "./fft"
},
{
"label": "ifft",
"url": "./ifft"
},
{
"label": "ifftshift",
"url": "./ifftshift"
},
{
"label": "circshift",
"url": "./circshift"
},
{
"label": "gpuArray",
"url": "./gpuarray"
},
{
"label": "gather",
"url": "./gather"
},
{
"label": "fft2",
"url": "./fft2"
},
{
"label": "ifft2",
"url": "./ifft2"
}
],
"source": {
"label": "`crates/runmat-runtime/src/builtins/math/fft/fftshift.rs`",
"url": "https://github.com/runmat-org/runmat/blob/main/crates/runmat-runtime/src/builtins/math/fft/fftshift.rs"
},
"gpu_residency": "RunMat's auto-offload keeps FFT spectra on the GPU whenever the active provider exposes the `circshift` hook. In that case `fftshift` runs entirely on the device and downstream fused operations continue without a gather. If no GPU provider is registered—or it does not expose `circshift`—RunMat gathers the data once, performs the host shift, and uploads the result back to the device so subsequent work can still benefit from acceleration. You can always call `gpuArray` explicitly when you need MATLAB compatibility or want to guarantee a specific residency boundary.",
"gpu_behavior": [
"RunMat asks the active acceleration provider to execute `fftshift` via the `circshift` hook (with predetermined offsets). If the provider cannot satisfy the request, the tensor is gathered exactly once, shifted on the host, and optionally re-uploaded. Scalars remain on their existing device."
]
}