Source code for deconvoluted.transforms

# -*- coding: utf-8 -*-
import numpy as np

from deconvoluted.conventions import Convention, signal

[docs]def determine_axes(f, *vars): """ Determine the axes along which the FT should be performed. """ if len(vars) != len(f.shape): raise TypeError('The number of variables has to match the dimension of ' '`f`. Use `None` for axis with respect to which no ' 'transform should be performed.') return [i for i, var in enumerate(vars) if var is not None]
[docs]def determine_norm(convention): """ Determine the normalization constant for this ``convention``. :param convention: tuple representing :math:`(a, b)`. :return: normalization constant. """ return np.sqrt(np.abs(convention.b) / (2 * np.pi) ** (1 - convention.a))
[docs]def fourier_transform(f, *vars, convention=signal): """ Performs the multidimensional Fourier transform of :math:`f(x_1, \ldots, x_n)` with respect to any number of variables :math:`x_i`. Examples:: # 1D transform F, k = fourier_transform(f, x) # 2D transform F_pq, p, q = fourier_transform(f_xy, x, y) # 2D function, transform only 1 axis F_py, p = fourier_transform(f_xy, x, None) :param f: array representing a function :math:`f(x_1, \ldots, x_n)` :param vars: list of :math:`x_i` w.r.t. which the Fourier transform has to be computed. In case of multi-dimensional functions :math:`f` the number of ``vars`` has to match the dimension of ``f``. Any axis that should be ignored should be provided as ``None``:: F_py, p = fourier_transform(f_xy, x, None) :param convention: The Fourier convention to be used. :math:`a=0` and :math:`b=- 2 \pi` by default, which is the signal processing standard. :return: :math:`F(k_1, \ldots, k_n)`, the Fourier transform of :math:`f(x_1, \ldots, x_n)`. """ convention = Convention(*convention) axes = determine_axes(f, *vars) F = np.fft.fftn(f, axes=axes, norm='ortho') F = np.fft.fftshift(F, axes=axes) F *= determine_norm(convention) # do the correct normalization ks = [] for x in vars: if x is None: continue d = x[1]-x[0] k = np.fft.fftfreq(len(x), d=d) k = np.fft.fftshift(k) # Go from -inf to inf k *= - (2 * np.pi) / convention.b # correct convention ks.append(k) return (F, *ks)
[docs]def inverse_fourier_transform(F, *vars, convention=signal): """ Perform an inverse Fourier transform. See :func:`deconvoluted.transforms.fourier_transform` for more info. :param F: Fourier transform :math:`F(k_1, \ldots, k_n)` of :math:`f(x_1, \ldots, x_n)`. :param vars: Any number of :math:`k` variables or ``None``. :param convention: The Fourier convention to be used. :math:`a=0` and :math:`b=- 2 \pi` by default, which is the signal processing standard. :return: :math:`f(x_1, \ldots, x_n)`, the inverse fourier transform of :math:`F(k_1, \ldots, k_n)` """ convention = Convention(*convention) # Make sure we have a Convention axes = determine_axes(F, *vars) f = np.fft.ifftshift(F, axes=axes) f = np.fft.ifftn(f, axes=axes, norm='ortho') f *= determine_norm(convention) / ((2 * np.pi)**convention.a) # do normalization f *= (2 * np.pi) / np.abs(convention.b) xs = [] for k in vars: if k is None: continue d = k[1] - k[0] x = np.fft.fftfreq(len(k), d=d) x = np.fft.fftshift(x) # Go from -inf to inf x *= - (2 * np.pi) / convention.b # correct convention xs.append(x) return (f, *xs)