首先介绍离散傅里叶变换(DFT),不管是正变换还是逆变换,计算公式可以归结为
X ( k ) = ∑ n = 0 N − 1 x ( n ) W N n k X(k)=\sum_{n=0}^{N-1}x(n)W_N^{nk} X(k)=n=0∑N−1x(n)WNnk
其中, N N N为抽样点的个数(一般为 2 n 2^n 2n), x ( n ) x(n) x(n)为已知数据(拟合函数时为节点函数值), W N = e − i 2 π n W_N=e^{-i\frac{2\pi}{n}} WN=e−in2π为旋转因子。
而快速傅里叶变换(FFT),只是对DFT在算法上进行一定的幼化,降低复杂度,同样可以总结为一个公式:
X ( k ) = { ∑ n = 0 N / 2 − 1 x 1 ( r ) W N / 2 r k + W N k ∑ n = 0 N / 2 − 1 x 2 ( r ) W N / 2 r k k = 0 , 1 , ⋯ , N 2 − 1 ∑ n = 0 N / 2 − 1 x 1 ( r ) W N / 2 r k ′ + W N k ′ ∑ n = 0 N / 2 − 1 x 2 ( r ) W N / 2 r k ′ k = k ′ + N 2 = N 2 , N 2 + 1 , ⋯ , N X(k)=\left\{ \begin{aligned} &\sum_{n=0}^{N/2-1}x_1(r)W_{N/2}^{rk}+W_N^{k}\sum_{n=0}^{N/2-1}x_2(r)W_{N/2}^{rk} \quad k=0,1,\cdots,\frac{N}{2}-1\\ &\sum_{n=0}^{N/2-1}x_1(r)W_{N/2}^{rk'}+W_N^{k'}\sum_{n=0}^{N/2-1}x_2(r)W_{N/2}^{rk'} \quad k=k'+\frac{N}{2}=\frac{N}{2},\frac{N}{2}+1,\cdots,N \end{aligned} \right. X(k)=⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧n=0∑N/2−1x1(r)WN/2rk+WNkn=0∑N/2−1x2(r)WN/2rkk=0,1,⋯,2N−1n=0∑N/2−1x1(r)WN/2rk′+WNk′n=0∑N/2−1x2(r)WN/2rk′k=k′+2N=2N,2N+1,⋯,N
import numpy as np
from numpy import pi
from numpy import exp
from numpy import cos, sin
import matplotlib.pyplot as plt
from pylab import mpl
def func(p: float):
return (p - pi) ** 2 * np.cos((p - pi)) # x = y - pi
def get_function(p: float, c: list, N: int):
a = [_ for _ in range(0, N)]
b = [_ for _ in range(0, N)]
res = 0
for k in range(0, N):
a[k] = (2 * c[k]).real
b[k] = -(2 * c[k]).imag
# print(a)
for k in range(1, N // 2):
res += a[k] * cos(k * p)
res += b[k] * sin(k * p)
res += a[0] / 2
res += b[N // 2] * sin(N // 2 * p)
return res
def solve_c(y: list, f: list, N: int):
c = [0 for _ in range(0, N)]
for k in range(0, N):
if k < N / 2:
c[k] = sum(f[0::2][i] / N * exp(-k * i * pi * 2j / (N // 2)) for i in range(0, N // 2)) \
+ sum(f[1::2][i] / N * exp(-k * i * pi * 2j / (N // 2)) for i in range(0, N // 2)) \
* exp(-k * pi * 2j / N)
# c[k] *= (-1) ** k
else:
kk = k - N / 2
c[k] = sum(f[0::2][i] / N * exp(-kk * i * pi * 2j / (N // 2)) for i in range(0, N // 2)) \
- sum(f[1::2][i] / N * exp(-kk * i * pi * 2j / (N // 2)) for i in range(0, N // 2)) \
* exp(-kk * pi * 2j / N)
# print(c)
return c
def draw(data: np.ndarray, x: list, f: list, N: int):
c = solve_c(y, f, N)
x = [_ - pi for _ in y]
plt.plot(data - pi, get_function(data, c, N), label="%s次三角插值拟合曲线" % str(N // 2), color="blue")
plt.scatter(x, f, label="节点数据", color="red")
plt.title("%s次三角插值拟合曲线" % str(N // 2))
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False
plt.legend(loc="upper right")
考虑 f ( x ) = x 2 cos x f(x)=x^2\cos{x} f(x)=x2cosx在 [ − π , π ] [-\pi,\pi] [−π,π]上的16次三角插值多项式
if __name__ == "__main__":
N = 2 * 16
y = [2 * pi / N * _ for _ in range(0, N)]
f = [func(_) for _ in y]
draw(np.arange(0, 2 * pi + 0.001, 0.001), y, f, N)
plt.plot(np.arange(-pi, pi + 0.001, 0.001), func(np.arange(0, 2 * pi + 0.001, 0.001)), color="black")
plt.show()
(建议直接放到上文代码底部实现)