傅里叶变换作用原理的详细解释
傅里叶变换作用原理的详细解释
傅里叶变换的内在原理
一、基底的原理
众所周知,对于任意一个函数来说,都可以将其分解为多个正弦函数和余弦函数相互叠加的形式,并使用欧拉公式进行转换,可以得到:
$$
f(x) = \frac{a_0}{2} + \sum_{n=1}^{\infty} \left( a_n \cos\left(\frac{2\pi nx}{T}\right) + b_n \sin\left(\frac{2\pi nx}{T}\right) \right)
$$
很明显,可以使用一组正交基来表示,即:
$$
B = \left{ \sin(w_1x), \cos(w_1x), \sin(w_2x), \cos(w_2x), \ldots, \sin(w_nx), \cos(w_nx) \right}
$$
其中,正交基的概念是:在一个周期内,它们任意两个的内积为0,即存在:
$$
\begin{split}
\int_{-\frac{T}{2}}^{\frac{T}{2}} \sin(w_1x) \sin(w_2x) dx &= 0 \quad w_1 \neq w_2 \
\int_{-\frac{T}{2}}^{\frac{T}{2}} \cos(w_1x) \cos(w_2x) dx &= 0 \quad w_1 \neq w_2 \
\int_{-\frac{T}{2}}^{\frac{T}{2}} \sin(w_1x) \cos(w_2x) dx &= 0 \
\end{split}
$$
换句话说,当某个时域函数 $f(x)$ 看成多个正弦和余弦函数的相互叠加后,如果需要判断某个三角函数是否存在,就只需要对其内积一个相同的三角函数。当内积之后的值为0时,则说明 $f(x)$ 中不存在这个三角函数,反之则存在。
二、基于欧拉公式的进一步理解
而在欧拉公式中,存在:
$$
e^{ix} = \cos{x} + i\sin{x}
$$
$f(x)$ 就可以修改为:
$$
f(x) = \sum_{n=-\infty}^{\infty} c_n \cdot e^{i\frac{2\pi nx}{T}} dx
$$
因此,可以将前面的基底 $B$ 简化成:
$$
B = \left{ 1, e^{w_1x}, e^{w_2x}, \ldots, e^{w_{n-1}x} \right}
$$
因此,当给予 $f(x)$ 分别内积矩阵 $B$ 的各个元素时,就能够判断各项因子是否存在。
此外,由于
$$
e^{-ix} = \cos(-x) + i\sin(-x) = \cos{x} - i\sin{x} = \hat{e}^{ix}
$$
所以,也能以 $\hat{B}$ 作为一组基底,而这个,也就是傅里叶变换的基底 $W_n^i$。
换个角度,$e^{ix}$ 和 $e^{-ix}$ 都是表示一个单位圆,只是,$e^{ix}$ 是沿逆时针旋转,而 $e^{-ix}$ 是沿顺时针旋转。
三、幅值和相位(傅里叶变换后的y、x轴)
3.1 幅值
前面说到,对 $f(x)$ 内积一个基底时,如果基底存在,那么它们的内积则不为0。这里以幅值为1的正弦函数作为举例,有:
$$
\begin{split}
&\int_{-\frac{T}{2}}^{\frac{T}{2}} \sin(w_ix) \sin(w_ix) dx \
=& \frac{1}{2} \int_{-\frac{T}{2}}^{\frac{T}{2}} 1 - \cos(2w_ix) dx \
=& \frac{T}{2}
\end{split}
$$
同理,就有:
$$
\begin{split}
a \int_{-\frac{T}{2}}^{\frac{T}{2}} \sin(w_ix) \cdot [-j \sin(w_ix)] dx &= -\frac{T}{2} ja \
a \int_{-\frac{T}{2}}^{\frac{T}{2}} \cos(w_ix) \cos(w_ix) dx &= \frac{T}{2} a \
\end{split}
$$
因此,就可以通过傅里叶变换得到的实部和虚部,就能分别判断余弦函数和正弦函数,以及对应的幅值 $a$。
3.2 相位
现在,再次从相位的角度去看基底。当内积一个基底 $W_n^i = e^{-j\frac{2\pi}{T}ix}$ 时,就说明此时基底的相位为 $\frac{1}{T}i$。因此,当内积不趋于0时,就说明 $f(x)$ 存在相同相位的函数。
四、代码实验
4.1 原理验证
这里,选择直接调用 fft
函数进行快速傅里叶变换,并假定时域采样数量与频域采样数量一致。
clc, clear
N = 3000; % 设置5000个采样点
x = linspace(0, 1, N); % 将0到1平分成5000份
y1 = 7 * sin(2 * pi * 300 * x) + ...
5 * sin(2 * pi * 400 * x) + ...
3 * sin(2 * pi * 600 * x) + 10; % 构造一个正弦组合信号,10为偏移信号
fft_y1 = fft(y1); % 使用快速傅里叶变换,得到的fft_y是长度为N的复数数组
freq_x = x * N;
plot(freq_x, w1)
w1 = zeros(1, N);
% 第一项为电流偏移信号
w1(1) = fft_y1(1) / N;
w1(2:end) = -imag(fft_y1(2:end)) / (N / 2);
plot(x, w1)
w1(w1<1&w1>-1) = 0;
freq_list1 = find(w1); % 找出不为0的数的下标
w1 = w1(freq_list1);
disp('相位为:')
disp(freq_list1 - 1)
disp('幅值为:')
disp(w1)
输出的图像和结果如下所示:
哎,相位和幅值数据为什么多了一半,而且幅值还互为相反数?
这是因为,基底采样数量是在一个周期的,即 $[0, T]$。这个解释起来很简单。就以基础的正弦函数来说,它是关于原点对称的。这也就意味着,当采样的角度范围为 $[0, \pi]$ 时,它实际上就能够基于一组基底,判断出所有的幅值。而当角度变为 $[\frac{T}{2}, T]$,它所计算出的值自然就关于 $\pi$ 即实例中的采样范围中心点 freq=1500 对称。
4.2 幅值精度优化
此外,可以看到,计算出的幅值与实际幅值差异有点大,这是因为实际计算中会产生累计的计算误差、以及相位偏移等因素影响。有什么方法可以提高精度呢?增加采样点数量?可以是可以,但这样也会大幅增加计算成本和数据成本。因此,一种很好的方法就是计算对应基底计算的总幅值,即看计算结果的模值。虽然,这种方法不能区分正弦函数和余弦函数单独的幅值,但是,它们的模值却可以表示两者合成后的总幅值,进而降低误差的影响。
w11 = abs(fft_y1);
w11(1) = w11(1) / N;
w11(2:end) = w11(2:end) / (N / 2);
w11(w11<1) = 0;
freq_list11 = find(w11); % 找出不为0的数的下标
w11 = w11(freq_list11);
disp('相位为:')
disp(freq_list11 - 1)
disp('幅值为:')
disp(w11)
4.3 正弦和余弦叠加的函数
最后,以一个复杂的叠加信号进行验证,从运行结果来看,猜想没有问题,只是,依旧存在较大误差,而它们叠加后的模值同样精度更高。
N = 30000;
x = linspace(0, 1, N);
y2 = 7 * sin(2 * pi * 300 * x) + 6 * cos(2 * pi * 300 * x) + ...
5 * sin(2 * pi * 400 * x) + 4 * cos(2 * pi * 400 * x) + ...
3 * sin(2 * pi * 600 * x) + 2 * cos(2 * pi * 600 * x) + 10; % 构造一个复杂的组合信号,10为偏移信号
fft_y2 = fft(y2); % 使用快速傅里叶变换
w2 = zeros(1, N);
w2(1) = fft_y2(1) / N;
w2(2:end) = conj(fft_y2(2:end)) / (N / 2);
w2(abs(w2)<1) = 0;
freq_list2 = find(w2);
w2 = w2(freq_list2);
disp('相位为:')
disp(freq_list2 - 1)
disp('幅值为:')
disp(w2)