简体   繁体   中英

Python: How to interpolate 'unstructured' 2D Fourier transform data

My goal is to interpolate the discretized continuous 2D Fourier transform of a function. The problem seems to be that the frequencies in each dimension are not output in strictly ascending order (see here ).

The fft.fft2 function accepts a 2D array, where in my case the array (let's call it A ) is structured such that A[i][j] = fun(x[i], y[j]) , fun being the function to be transformed. After applying fft.fft2 to A , output is an array F of the same dimensions as the original array, such that the frequency coordinate corresponding to F[i][j] is (w_x[i], w_y[j]) , where w_x = fft.fftfreq(F.shape[0]) and w_y = fft.fftfreq(F.shape[1]) , both of these being 1D arrays which are not in ascending order.

Over wx and wy I am wanting to interpolate F (say to a function finterp ) such that the interpolated value is returned upon calling finterp(w_x, w_y) , w_x and w_y being within the domain of wx and range of wy , but otherwise arbitrary. I've looked into the varieties of interpolation available through scipy.interpolate , but it doesn't seem to me that any of them can deal with this type of data structure (the coordinate axes being defined as out-of-order 1D arrays and the function values being in a 2D array).

This is a little abstract, so here I've made up a simple example which is similar in structure to the above. Suppose we are wishing to construct a continuous function f(x, y) = x + y over the region x = [-1, 1] and y = [-1, 1] given the following data:

import numpy as np

# note that below z[i][j] corresponds to what we want f(x[i], y[j]) to be

x = np.array([0, 1, -1])
y = np.array([0, 1, -1])
z = np.array([0, 1, -1],[1, 2, 0],[-1, 0, -2])

z[i][j] we know corresponds to the function evaluated at x[i], y[j] . How can one either (a) interpolate this data directly, given its original structure, or (b) rearrange the data so that x and y are in ascending order, and the arranged z is such that z[i][j] is equal to the function evaluated at the rearranged x[i], y[j] ?

The following code shows how to use fftshift to change the output of fft2 and fftfreq so that the frequency axes are monotonically increasing. After applying fftshift , you can use the arrays for interpolation. I've added display of the arrays so that you can verify that the data itself is unchanged. The origin is shifted from the top-left corner to the middle of the array, moving the negative frequencies from the right side to the left side.

import numpy as np
import matplotlib.pyplot as pp

x = np.array([0, 1, -1])
y = np.array([0, 1, -1])
z = np.array([[0, 1, -1],[1, 2, 0],[-1, 0, -2]])
f = np.fft.fft2(z)
w_x = np.fft.fftfreq(f.shape[0])
w_y = np.fft.fftfreq(f.shape[1])

pp.figure()
pp.imshow(np.abs(f))
pp.xticks(np.arange(0,len(w_x)), np.round(w_x,2))
pp.yticks(np.arange(0,len(w_y)), np.round(w_y,2))

f = np.fft.fftshift(f)
w_x = np.fft.fftshift(w_x)
w_y = np.fft.fftshift(w_y)

pp.figure()
pp.imshow(np.abs(f))
pp.xticks(np.arange(0,len(w_x)), np.round(w_x,2))
pp.yticks(np.arange(0,len(w_y)), np.round(w_y,2))
pp.show()

An alternative approach is to not use fftfreq to determine your frequencies, but compute them by hand. The FFT, by default, computes the DFT for k=[0..N-1] . Because of the periodicity, with the DFT at k equal to the DFT at k+N and kN , its output is often interpreted to have k=[N//2...(N-1)//2] instead (but arranged differently to match k=[0..N-1] ); this is the k that fftfreq returns (it returns k/N ).

Thus, you can instead say

N = f.shape[0]
w_x = np.linspace(0, N, N, endpoint=False) / N

Now you don't have any negative frequencies, and instead have frequencies in the range [0,N-1]/N .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM