Properties of the Fourier Transform

In this article, we will illustrate several basic properties of the Fourier Transform, which are essential for working with the transform from day to day. First, let us define a Python function which approximates the Fourier transform

$$ X(f) = \int_{-\infty}^{\infty}x(t)\exp(-j2\pi ft) dt $$

from a sampled version $x(\frac{n}{F_s}-t_0), n=0,\dots,N-1$ of the signal, by using the discrete Fourier transform (refer to Approximation of Fourier Transform with DFT for an explanation):

def ft(samples, Fs, t0):
    """Approximate the Fourier Transform of a time-limited signal 
    by means of the discrete Fourier Transform.
    
    samples: signal values sampled at the positions t0 + n/Fs
    Fs: Sampling frequency of the signal
    t0: starting time of the sampling of the signal
    """
    f = np.linspace(-Fs/2, Fs/2, len(samples), endpoint=False)
    return np.fft.fftshift(np.fft.fft(samples)/Fs * np.exp(-2j*np.pi*f*t0))

Some basic correspondences

Let us start with some basic known correspondences of the Fourier Transform and plot these to ensure the correctnes of our Fourier Transform function.

Fs = 10000  # The sampling frequency we use for the simulation
t0 = 10     # The half time interval we look at
t = np.arange(-t0, t0, 1/Fs)  # the time samples
f = np.arange(-Fs/2, Fs/2, Fs/len(t))  # the corresponding frequency samples
g = lambda t: (abs(t) <=0.5).astype(float)  # define rect function
plt.subplot(121)
plt.plot(t, g(t))

plt.subplot(122)
plt.plot(f, ft(g(t), Fs, -t0).real)
g = lambda t: np.sin(2*np.pi*2*t)
plt.subplot(121)
plt.plot(t, g(t))

plt.subplot(122)
plt.plot(f, ft(g(t), Fs, -t0).real, label='real')
plt.plot(f, ft(g(t), Fs, -t0).imag, label='imag')
g = lambda t: np.cos(3*np.pi*2*t)
plt.subplot(121)
plt.plot(t, g(t))

plt.subplot(122)
plt.plot(f, ft(g(t), Fs, -t0).real, label='real')
plt.plot(f, ft(g(t), Fs, -t0).imag, label='imag')
g = lambda t: np.exp(-abs(t*t))
plt.subplot(121)
plt.plot(t, g(t))

plt.subplot(122)
plt.plot(f, ft(g(t), Fs, -t0).real, label='real')
plt.plot(f, ft(g(t), Fs, -t0).imag, label='imag')
g = lambda t: np.sinc(t)**2
plt.subplot(121)
plt.plot(t, g(t))

plt.subplot(122)
plt.plot(f, ft(g(t), Fs, -t0).real, label='real')
plt.plot(f, ft(g(t), Fs, -t0).imag, label='imag')
plt.tight_layout()

Linearity of the Fourier Transform

The Fourier Transform is a linear operation, i.e. it does not matter if you perform scaling and summation of two functions before or after Fourier Transform. Let $x(t)$ and $y(t)$ be two signals. Then the following holds:

\begin{align} \mathcal{F}\{x(t)\} &= X(f) \\ \mathcal{F}\{y(t)\} &= Y(f) \\ \mathcal{F}\{ax(t)+by(t)\} &= aX(f)+bY(f) \\ \end{align}

Let us verify this operation numerically by calculating the Fourier transform of a the sum of a rect plus a Gaussian:

def rect(t):
    return (abs(t) <= 0.5).astype(float)
def gauss(t):
    return np.exp(-t*t)
def triang(t):
    return (1-abs(t)) * rect(t/2)


tstart = 10
Fs = 1000
t = np.arange(-tstart, tstart, 1/Fs)
f = np.arange(-Fs/2, Fs/2, Fs/len(t))

x = rect
y = gauss
X = ft(x(t), Fs, -tstart)
Y = ft(y(t), Fs, -tstart)

def showLinearity(a):
    plt.subplot(221)
    plt.plot(t, x(t), label='$x(t)$')
    plt.plot(t, y(t), label='$y(t)$')

    plt.subplot(222)
    plt.plot(f, X.real, label='$X(f)$')
    plt.plot(f, Y.real, label='$Y(f)$')
    
    xplusay = lambda t: x(t) + a*y(t)
    XplusaY = ft(xplusay(t), Fs, -t0)
    plt.subplot(223)
    plt.plot(t, xplusay(t), '-*', label='$x(t)+ay(t)$', markevery=400)
    plt.plot(t, x(t), label='$x(t)$')
    plt.plot(t, a*y(t), label='$ay(t)$')
    
    plt.subplot(224)
    plt.plot(f, XplusaY.real, '-*', label='$X(f)+aY(f)$', markevery=10)
    plt.plot(f, X.real, label='$X(f)$')
    plt.plot(f, a*Y.real, label='$aY(f)$')
 

As visible, the Fourier Transform of a linear combination of two input signals is the same linear combination of the Fourier Transforms of the input signal.

Time-shifting property of the Fourier Transform

The time-shifting property means that a shift in time corresponds to a phase rotation in the frequency domain:

$$\mathcal{F}\{x(t-t_0)\} = \exp(-j2\pi ft_0)X(f). $$

Let us verify this property numerically with the code below. For example, see that for a time-shift of 1s, in the spectrum the phase rotates by one full period every Hz.

x = rect
X = ft(x(t), Fs, -tstart)

def showShift(t0):
    plt.gcf().clear()
    
    plt.subplot(121)
    plt.plot(t, x(t), label='$x(t)$')
    plt.plot(t, x(t-t0), label='$x(t-t_0)$')
    

    plt.subplot(122)
    Xt0 = ft(x(t-t0), Fs, -tstart)
    plt.plot(f, X.real, label='Re $X(f)$')
    plt.plot(f, Xt0.real, label='Re $X_{t_0}(f)$')
    plt.plot(f, Xt0.imag, label='Im $X_{t_0}(f)$')