Skip to content

Commit

Permalink
Add ifft with test and doc.
Browse files Browse the repository at this point in the history
  • Loading branch information
atrabattoni committed Dec 2, 2024
1 parent 19be6b4 commit f900984
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/api/fft.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@
:toctree: ../_autosummary
fft
ifft
rfft
```
18 changes: 18 additions & 0 deletions tests/test_fft.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,21 @@ def test_with_non_dimensional(self):
da = xd.synthetics.wavelet_wavefronts()
da["latitude"] = ("distance", np.arange(da.sizes["distance"]))
xfft.rfft(da)


class TestIFFT:
def test_base(self):
expected = xd.synthetics.wavelet_wavefronts()
result = xfft.ifft(
xfft.fft(expected, dim={"time": "frequency"}), dim={"frequency": "time"}
)
assert np.allclose(np.real(result).values, expected.values)
assert np.allclose(np.imag(result).values, 0)
for name in result.coords:
if name == "time":
ref = expected["time"].values
ref = (ref - ref[0]) / np.timedelta64(1, "s")
ref += result["time"][0].values
assert np.allclose(result["time"].values, ref)
else:
assert result[name].equals(expected[name])
57 changes: 57 additions & 0 deletions xdas/fft.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,60 @@ def rfft(da, n=None, dim={"last": "frequency"}, norm=None, parallel=None):
}
dims = tuple(newdim if dim == olddim else dim for dim in da.dims)
return DataArray(data, coords, dims, da.name, da.attrs)


@atomized
def ifft(da, n=None, dim={"last": "time"}, norm=None, parallel=None):
"""
Compute the inverse discrete Fourier Transform along a given dimension.
This function computes the inverse of the one-dimensional n-point discrete Fourier
transform computed by fft. In other words, ifft(fft(a)) == a to within numerical
accuracy.
Parameters
----------
da: DataArray
The data array to process, should be complex.
n: int, optional
Length of transformed dimension of the output. If n is smaller than the length
of the input, the input is cropped. If it is larger, the input is padded with
zeros. If n is not given, the length of the input along the dimension specified
by `dim` is used.
dim: {str: str}, optional
A mapping indicating as a key the dimension along which to compute the IFFT, and
as value the new name of the dimension. Default to {"last": "spectrum"}.
norm: {“backward”, “ortho”, “forward”}, optional
Normalization mode (see `numpy.fft`). Default is "backward". Indicates which
direction of the forward/backward pair of transforms is scaled and with what
normalization factor.
Returns
-------
DataArray:
The transformed input with an updated dimension name and values.
Notes
-----
- To perform a multidimensional inverse fourrier transform, repeat this function on
the desired dimensions.
"""
((olddim, newdim),) = dim.items()
olddim = da.dims[da.get_axis_num(olddim)]
if n is None:
n = da.sizes[olddim]
axis = da.get_axis_num(olddim)
d = get_sampling_interval(da, olddim)
f = np.fft.ifftshift(np.fft.fftfreq(n, d))
func = lambda x: np.fft.ifft(np.fft.ifftshift(x, axis), n, axis, norm)
across = int(axis == 0)
func = parallelize(across, across, parallel)(func)
data = func(da.values)
coords = {
newdim if name == olddim else name: f if name == olddim else da.coords[name]
for name in da.coords
if (da[name].dim != olddim or name == olddim)
}
dims = tuple(newdim if dim == olddim else dim for dim in da.dims)
return DataArray(data, coords, dims, da.name, da.attrs)

0 comments on commit f900984

Please sign in to comment.