Skip to article frontmatterSkip to article content

Trigonometric interpolation

from pylab import *

1Interpolation problem

For any even integer N>0N>0, consider the set of points

xj=2πjN,j=0,1,,N1x_j = \frac{2\pi j}{N}, \qquad j=0,1,\ldots,N-1

The degree N/2N/2 trigonometric polynomial is

INu(x)=k=N/2N/21u~kϕk(x)=k=N/2N/21u~keikxI_N u(x) = \sumf \tilu_k \phi_k(x) = \sumf \tilu_k \ee^{\ii k x}

We will determine the coefficients from the interpolation conditions

u(xj)=INu(xj),j=0,1,,N1u(x_j) = I_N u(x_j), \qquad j=0,1,\ldots,N-1

Using the orthogonality relation

1Nj=0N1eipxj={1,p=Nm,m=0,±1,±2,0,otherwise\frac{1}{N} \sum_{j=0}^{N-1} \ee^{-\ii p x_j} = \begin{cases} 1, & p = Nm, \quad m=0, \pm 1, \pm 2, \ldots \\ 0, & \textrm{otherwise} \end{cases}

we obtain the discrete Fourier coefficients

u~k=1Nj=0N1u(xj)eikxj,k=N/2,,N/21\tilu_k = \frac{1}{N} \sum_{j=0}^{N-1} u(x_j) \ee^{-\ii k x_j}, \qquad k=-N/2, \ldots, N/2 - 1

We can derive a Lagrange form of the interpolation as follows.

INu(x)=k=N/2N/21u~keikx=1Nk=N/2N/21j=0N1u(xj)eik(xxj)=j=0N1u(xj)1Nk=N/2N/21eik(xxj)=j=0N1u(xj)ψj(x)\begin{aligned} I_N u(x) &= \sumf \tilu_k \ee^{\ii k x} \\ &= \frac{1}{N} \sumf \sum_{j=0}^{N-1} u(x_j) \ee^{\ii k (x-x_j)} \\ &= \sum_{j=0}^{N-1} u(x_j) \frac{1}{N} \sumf \ee^{\ii k (x-x_j)} \\ &= \sum_{j=0}^{N-1} u(x_j) \psi_j(x) \end{aligned}

where

ψj(x)=1Nk=N/2N/21eik(xxj)\psi_j(x) = \frac{1}{N} \sumf \ee^{\ii k (x-x_j)}

The functions ψj\psi_j are trigonometric polynomials in SNS_N that satisfy

ψj(xl)=δjl,0j,lN1\psi_j(x_l) = \delta_{jl}, \qquad 0 \le j,l \le N-1

Define the discrete inner product

(u,v)N=2πNj=0N1u(xj)v(xj)\ip{u,v}_N = \frac{2\pi}{N} \sum_{j=0}^{N-1} u(x_j) \conj{v(x_j)}

As a consequence, (,)N\ip{\cdot,\cdot}_N is an inner product on SNS_N and

uN:=(u,u)N=(u,u)=u,uSN\norm{u}_N := \sqrt{\ip{u,u}_N} = \sqrt{\ip{u,u}} = \norm{u}, \qquad \forall u \in S_N

Hence the interpolant satifies

(INuu,v)N=0,vSN\ip{I_N u - u, v}_N = 0, \qquad \forall v \in S_N

Thus INuI_N u is the orthogonal projection of uu onto SNS_N with respect to the discrete inner product.

2Computing the DFT

If the function uu is real, then the DFT comes in complex conjugate pairs

u^k=u^k,1kN/21\hatu_{-k} = \conj{\hatu_k}, \qquad 1 \le k \le N/2-1

and u^0\hatu_0, u^N/2\hatu_{-N/2} are real. The first property is easy. We have

u^0=1Nj=0N1u(xj)\hatu_0 = \frac{1}{N} \sum_{j=0}^{N-1} u(x_j)

which is real, and

u^N/2=1Nj=0N1u(xj)eiπj\hatu_{-N/2} = \frac{1}{N} \sum_{j=0}^{N-1} u(x_j) \ee^{\ii \pi j}

is also real. When we want to evaluate INu(x)I_N u(x) at some arbitrary xx, we should modify it as

INu(x)=k=N/2N/2u^keikxI_N u(x) = {\sum_{k=-N/2}^{N/2}}^\prime \hatu_k \ee^{\ii k x}

where u^N/2=u^N/2\hatu_{N/2} = \hatu_{-N/2} and the prime denotes that the first and last terms must be multiplied by half. This ensures that the interpolation conditions are satisfied and INu(x)I_N u(x) is real for all x[0,2π]x \in [0,2\pi].

Numpy has routines to compute the DFT using FFT. It takes the trigonometric polynomial in the form

INu(x)=k=N/2+1N/2u^keikxI_N u(x) = \sum_{k=-N/2+1}^{N/2} \hatu_k \ee^{\ii k x}

which is different from our convention.

from numpy import pi,arange
import numpy.fft as fft
h = 2*pi/N; x = h*arange(0,N);
u = f(x);
u_hat = fft(v)

The output u_hat gives the DFT in the following order

u^0, u^1, , u^N/2, u^N/2+1, , u^2, u^1\hatu_0, \ \hatu_1, \ \ldots, \ \hatu_{N/2}, \ \hatu_{-N/2+1}, \ \ldots, \ \hatu_{-2}, \ \hatu_{-1}

See more examples here http://cpraveen.github.io/teaching/chebpy.html

3Examples

The following function computes the trigonometric interpolant and plots it.

# Wave numbers are arranged as k=[0,1,...,N/2,-N/2+1,-N/2,...,-1]
def fourier_interp(N,f,ne=500,fig=True):
    if mod(N,2) != 0:
        print("N must be even")
        return
    h = 2*pi/N; x = h*arange(0,N);
    v = f(x);
    v_hat = fft(v)
    k = zeros(N)
    n = int(N/2)
    k[0:n+1] = arange(0,n+1)
    k[n+1:] = arange(-n+1,0,1)

    xx = linspace(0.0,2*pi,ne)
    vf = real(dot(exp(1j*outer(xx,k)), v_hat)/N)
    ve = f(xx)

    # Plot interpolant and exact function
    if fig:
        plot(x,v,'o',xx,vf,xx,ve)
        legend(('Data','Fourier','Exact'))
        xlabel('x'), ylabel('y'), title("N = "+str(N))

    errori = abs(vf-ve).max()
    error2 = sqrt(h*sum((vf-ve)**2))
    print("Error (max,L2) = ",errori,error2)
    return errori, error2

4Infintely smooth, periodic function

f1 = lambda x: exp(sin(x))
fourier_interp(24,f1);
Error (max,L2) =  8.01581023779363e-14 4.567409062002914e-13
<Figure size 640x480 with 1 Axes>

5Infinitely smooth, derivative not periodic

g = lambda x: sin(x/2)
e1i,e12 = fourier_interp(24,g)
Error (max,L2) =  0.024794983262922628 0.0690760697875046
<Figure size 640x480 with 1 Axes>
e2i,e22 = fourier_interp(48,g,fig=False)
print("Rate (max,L2) = ", log(e1i/e2i)/log(2), log(e12/e22)/log(2))
Error (max,L2) =  0.012409450043334757 0.017665433009611695
Rate (max,L2) =  0.9986090713583914 1.9672568878077012

6Continuous function

def trihat(x):
    f = 0*x
    for i in range(len(x)):
        if x[i] < 0.5*pi or x[i] > 1.5*pi:
            f[i] = 0.0
        elif x[i] >= 0.5*pi and x[i] <= pi:
            f[i] = 2*x[i]/pi - 1
        else:
            f[i] = 3 - 2*x[i]/pi
    return f

e1i,e12 = fourier_interp(24,trihat)
Error (max,L2) =  0.0319508570865632 0.11143948223105607
<Figure size 640x480 with 1 Axes>
e2i,e22 = fourier_interp(48,trihat,fig=False)
print("Rate (max,L2) = ", log(e1i/e2i)/log(2), log(e12/e22)/log(2))
Error (max,L2) =  0.015806700636915583 0.02810440673007998
Rate (max,L2) =  1.0153183695992805 1.9873921942542283

7Discontinuous function

f2 = lambda x: (abs(x-pi) < 0.5*pi)
e1i,e12 = fourier_interp(24,f2)
Error (max,L2) =  0.9915112319641802 2.0366611449817986
<Figure size 640x480 with 1 Axes>
e2i,e22 = fourier_interp(48,f2)
print("Rate (max,L2) = ", log(e1i/e2i)/log(2), log(e12/e22)/log(2))
Error (max,L2) =  0.9828401566916884 1.0415601456207677
Rate (max,L2) =  0.0126723113206373 0.9674598167513291
<Figure size 640x480 with 1 Axes>