一只小松福 發表於 2019-9-20 19:18:00

快速傅里叶变换及python代码实现

<h1>一、前言</h1>
<p>  我想认真写好快速傅里叶变换(Fast Fourier Transform,FFT),所以这篇文章会由浅到细,由窄到宽的讲解,但是傅里叶变换对于寻常人并不是很容易理解的,所以对于基础不牢的人我会通过前言普及一下相关知识。</p>
<p>  我们复习一下三角函数的标准式:</p>
<p>$$y=A\cos (\omega x+\theta&nbsp;)+k$$</p>
<p>  $A$代表<strong>振幅</strong>,函数周期是$\frac{2\pi}{w}$,<strong>频率</strong>是周期的倒数$\frac{w}{2\pi}$,$\theta&nbsp;$是函数<strong>初相位</strong>,$k$在信号处理中称为直流分量。这个信号在<strong>频域</strong>就是一条竖线。</p>
<p>  我们再来假设有一个比较复杂的时域函数$y=f(t)$,根据傅里叶的理论,<span style="color: rgba(255, 0, 0, 1)">任何一个周期函数可以被分解为一系列<strong>振幅</strong>A,<strong>频率</strong><span data-content="ω">$\omega$或初<strong>相位</strong><span data-content="φ">$\theta $</span></span>正弦函数的叠加</span></p>
<p><span data-content="ω">$$y = A_1sin(\omega_1t+\theta_1) +&nbsp; A_2sin(\omega_2t+\theta_2) +&nbsp; A_3sin(\omega_3t+\theta_3)$$</span></p>
<p>  该信号在频域有三条竖线组成,而竖线图我们把它称为<strong>频谱图</strong>,大家可以通过下面的动画了解</p>
<p style="text-align: center"><img src="https://img2020.cnblogs.com/blog/1433301/202003/1433301-20200323224552496-431829120.gif" alt=""></p>
<p style="text-align: center"><img src="https://img2020.cnblogs.com/blog/1433301/202003/1433301-20200323230412598-718473696.jpg" alt="" width="574" height="345"></p>
<p>  如图可知,通过时域到频域的变换,我们得到了一个从侧面看的频谱,但是这个频谱并没有包含时域中全部的信息。因为<span style="color: rgba(0, 0, 255, 1)"><strong>频谱只代表每个正弦波对应频率的振幅</strong></span>是多少,而没有提到相位。<span style="color: rgba(255, 0, 0, 1)"><strong>基础的正弦波$Asin(wt+\theta&nbsp;)$中,振幅,频率,相位缺一不可</strong></span>,<span style="color: rgba(0, 0, 255, 1)"><strong>不同相位决定了波的位置</strong></span>,所以对于频域分析,仅仅有频谱(振幅谱)是不够的,我们还需要一个相位谱。</p>
<p>  我依稀记得高中学正弦函数的是时候,$\theta $的多少决定了正弦波向右移动多少。当然那个时候横坐标是相位角度,而时域信号的横坐标是时间,因此我们只需要将时间转换为相位角度就得到了初相位。<span style="color: rgba(128, 128, 128, 1)">相位差则是时间差在一个周期中所占的比例</span></p>
<p>$$\theta=2\pi \frac{t}{T}$$</p>
<p><img src="https://img2020.cnblogs.com/blog/1433301/202003/1433301-20200323235431809-993732380.jpg" alt="" width="417" height="359" style="display: block; margin-left: auto; margin-right: auto"></p>
<p>  所以傅里叶变换可以把一个比较复杂的函数转换为多个简单函数的叠加,<strong>将时域(即时间域)上的信号转变为频域(即频率域)上的信号</strong>,看问题的角度也从时间域转到了频率域,因此在时域中某些不好处理的地方,在频域就可以较为简单的处理,这就可以大量减少处理信号计算量。<span style="color: rgba(255, 0, 0, 1)">信号经过傅里叶变换后,可以得到频域的<strong>幅度谱</strong>以及<strong>相位谱</strong>,信号的<strong>幅度谱</strong>和<strong><strong>相位谱</strong></strong>是信号傅里叶变换后频谱的<strong>两个属性</strong></span>。</p>
<p><strong>傅里叶用途</strong></p>
<ul>
<li>时域复杂的函数,在频域就是几条竖线</li>
<li>求解微分方程,傅里叶变换则可以让微分和积分在频域中变为乘法和除法</li>
</ul>
<h2>傅里叶变换相关函数</h2>
<p>  假设我们的输入信号的函数是</p>
<p>$$S=0.2+0.7*\cos (2\pi*50t+\frac{20}{180}\pi)+0.2*\cos (2\pi*100t+\frac{70}{180}\pi)$$</p>
<p>可以发现直流分量是0.2,以及两个余弦函数的叠加,余弦函数的幅值分别为0.7和0.2,频率分别为50和100,初相位分别为20度和70度。</p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong>freqs = np.fft.fftfreq(采样数量, 采样周期)</strong></span>  通过采样数与采样周期得到时域序列经过傅里叶变换后的<strong>频率序列</strong></p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong><strong>np.fft</strong>.fft(原序列)</strong></span>  原函数值的序列经过快速傅里叶变换得到一个复数数组,<strong>复数的模代表的是振幅,复数的辐角代表初相位</strong></p>
<p><span style="color: rgba(255, 0, 0, 1)"><strong><strong>np.fft</strong>.ifft(复数序列)</strong></span>  复数数组 经过逆向傅里叶变换得到合成的函数值数组</p>
<p>案例:针对合成波做快速傅里叶变换,得到分解波数组的频率、振幅、初相位数组,并绘制频域图像。</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt="" id="code_img_closed_9144207d-9a1e-4207-8b21-8ae595036750" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="" id="code_img_opened_9144207d-9a1e-4207-8b21-8ae595036750" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_9144207d-9a1e-4207-8b21-8ae595036750" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> matplotlib.pyplot as plt
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> numpy as np
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> numpy.fft as fft

plt.rcParams[</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">font.sans-serif</span><span style="color: rgba(128, 0, 0, 1)">'</span>]=[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">SimHei</span><span style="color: rgba(128, 0, 0, 1)">'</span>] <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">用来正常显示中文标签</span>
plt.rcParams[<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">axes.unicode_minus</span><span style="color: rgba(128, 0, 0, 1)">'</span>]=False <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">用来正常显示符号</span>
<span style="color: rgba(0, 0, 0, 1)">
Fs </span>= 1000;            <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 采样频率</span>
T = 1/Fs;             <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 采样周期</span>
L = 1000;             <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 信号长度</span>
t =
t </span>=<span style="color: rgba(0, 0, 0, 1)"> np.array(t)

S </span>= 0.2+0.7*np.cos(2*np.pi*50*t+20/180*np.pi) + 0.2*np.cos(2*np.pi*100*t+70/180*<span style="color: rgba(0, 0, 0, 1)">np.pi) ;


complex_array </span>=<span style="color: rgba(0, 0, 0, 1)"> fft.fft(S)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(complex_array.shape)<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> (1000,) </span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(complex_array.dtype)<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> complex128 </span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(complex_array)<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> (-2.360174309695419e-14+2.3825789764340993e-13j)</span>

<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">################################</span>
plt.subplot(311<span style="color: rgba(0, 0, 0, 1)">)
plt.grid(linestyle</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.plot(</span>1000*t, S, label=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">S</span><span style="color: rgba(128, 0, 0, 1)">'</span>)<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> y是1000个相加后的正弦序列</span>
plt.xlabel(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">t(毫秒)</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
plt.ylabel(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">S(t)幅值</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
plt.title(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">叠加信号图</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
plt.legend()

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">##################################</span>
plt.subplot(312<span style="color: rgba(0, 0, 0, 1)">)
S_ifft </span>=<span style="color: rgba(0, 0, 0, 1)"> fft.ifft(complex_array)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> S_new是ifft变换后的序列</span>
plt.plot(1000*t, S_ifft, label=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">S_ifft</span><span style="color: rgba(128, 0, 0, 1)">'</span>, color=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">orangered</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.xlabel(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">t(毫秒)</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
plt.ylabel(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">S_ifft(t)幅值</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
plt.title(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">ifft变换图</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
plt.grid(linestyle</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.legend()

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)">##################################</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 得到分解波的频率序列</span>
freqs = fft.fftfreq(t.size, t -<span style="color: rgba(0, 0, 0, 1)"> t)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 复数的模为信号的振幅(能量大小)</span>
pows =<span style="color: rgba(0, 0, 0, 1)"> np.abs(complex_array)

plt.subplot(</span>313<span style="color: rgba(0, 0, 0, 1)">)
plt.title(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">FFT变换,频谱图</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.xlabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Frequency 频率</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.ylabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Power 功率</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.tick_params(labelsize</span>=10<span style="color: rgba(0, 0, 0, 1)">)
plt.grid(linestyle</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.plot(freqs, pows, c=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">orangered</span><span style="color: rgba(128, 0, 0, 1)">'</span>, label=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Frequency</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.legend()
plt.tight_layout()
plt.show()</span></pre>
</div>
<span class="cnblogs_code_collapse">python代码实现</span></div>
<p><img src="https://img2020.cnblogs.com/blog/1433301/202003/1433301-20200324170130933-1478675962.png" alt="" width="585" height="433" style="display: block; margin-left: auto; margin-right: auto"></p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt="" id="code_img_closed_2e5b1558-0b03-4b46-bd4e-f2a1c27c7bcd" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="" id="code_img_opened_2e5b1558-0b03-4b46-bd4e-f2a1c27c7bcd" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_2e5b1558-0b03-4b46-bd4e-f2a1c27c7bcd" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 0, 1)">clear
clc
close all
Fs </span>= 1000;            %<span style="color: rgba(0, 0, 0, 1)"> Sampling frequency
T </span>= 1/Fs;             %<span style="color: rgba(0, 0, 0, 1)"> Sampling period
L </span>= 1000;             %<span style="color: rgba(0, 0, 0, 1)"> Length of signal
t </span>= (0:L-1)*T;      %<span style="color: rgba(0, 0, 0, 1)"> Time vector
S </span>= 0.2-0.7*cos(2*pi*50*t+20/180*pi) + 0.2*cos(2*pi*100*t+70/180*<span style="color: rgba(0, 0, 0, 1)">pi) ;
plot(</span>1000*t(1:50),S(1:50<span style="color: rgba(0, 0, 0, 1)">))
title(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">叠加信号图</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
xlabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">t (milliseconds)</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
ylabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">S(t)</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)

figure
Y </span>=<span style="color: rgba(0, 0, 0, 1)"> fft(S);
P2 </span>= abs(Y/<span style="color: rgba(0, 0, 0, 1)">L);
P1 </span>= P2(1:L/2+1<span style="color: rgba(0, 0, 0, 1)">);
P1(</span>2:end-1) = 2*P1(2:end-1<span style="color: rgba(0, 0, 0, 1)">);
f </span>= Fs*(0:(L/2))/<span style="color: rgba(0, 0, 0, 1)">L;
plot(f,P1,</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">linewidth</span><span style="color: rgba(128, 0, 0, 1)">'</span>,2<span style="color: rgba(0, 0, 0, 1)">)
title(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">FFT变换</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
xlabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">频率(Hz)</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
ylabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">幅值</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)

figure
pred_X</span>=<span style="color: rgba(0, 0, 0, 1)">ifft(Y);
plot(</span>1000*t(1:50),pred_X(1:50),<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">r-</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<span class="cnblogs_code_collapse">MATLAB实现</span></div>
<p><span class="classifier-delimiter">补充一些复数知识<strong>(很重要)</strong>:</span></p>
<p><span class="classifier-delimiter">1、复数$S$的几种表示形式:</span></p>
<ul>
<li><span class="classifier-delimiter">实部、虚部(直角坐标系):$a+bj$  &nbsp; &nbsp; ($a$是实部,$b$是虚部)</span></li>
<li><span class="classifier-delimiter">幅值、相位(指数系):$re^{j\theta }$  ($r$是幅值,$\theta$是相角,$e^{j\theta }$是相位)</span></li>
<li><span class="classifier-delimiter">极坐标表示法:$r\angle \theta&nbsp;$</span></li>
<li><span class="classifier-delimiter">指数系$&lt;--&gt;$指教坐标系:$re^{j\theta }=r(cos\theta+jsin\theta)=rcos\theta+jrsin\theta$</span></li>
</ul>
<p><span class="classifier-delimiter">  因此,我们可以通过以下方法得到:</span></p>
<p><span class="classifier-delimiter"><strong>实部</strong>: $a=rcos\theta$,&nbsp;<span class="cnblogs_code">real = np.real(S)</span>&nbsp;</span></p>
<p><span class="classifier-delimiter"><strong>虚部</strong>: $b=rsin\theta$,&nbsp;<span class="cnblogs_code">imag= np.imag(S)</span>&nbsp;</span></p>
<p><span class="classifier-delimiter"><strong>幅值</strong>:$r=\sqrt{a^2+b^2}$,&nbsp;<span class="cnblogs_code">magnitude = np.abs(S)</span>&nbsp; 或&nbsp;&nbsp;<span class="cnblogs_code">magnitude = np.sqrt(real**<span style="color: rgba(128, 0, 128, 1)">2</span>+imag**<span style="color: rgba(128, 0, 128, 1)">2</span>)</span>&nbsp;</span></p>
<p><span class="classifier-delimiter"><strong>相角</strong><span style="color: rgba(136, 136, 136, 1)">(以弧度为单位rad)</span>:$\theta=tan^{-1}(\frac{b}{a})$ 或 $\theta=atan2(b,a)$。&nbsp;<span class="cnblogs_code">angle = np.angle(D(F, T))</span>&nbsp;</span></p>
<p><span class="classifier-delimiter"><strong>相角</strong><span style="color: rgba(136, 136, 136, 1)">(以角度为单位deg)</span>:$deg = rad*\frac{180}{\pi}$,$\text{rad2deg}(\text{atan2}(b,a))$。&nbsp;<span class="cnblogs_code">deg = rad * <span style="color: rgba(128, 0, 128, 1)">180</span>/np.pi </span>&nbsp;</span></p>
<p><strong>相位</strong>:&nbsp;<span class="cnblogs_code">phase = np.exp(1j * np.angle(S))</span>&nbsp;</p>
<h2>基于傅里叶变换的<span style="color: rgba(255, 0, 0, 1)">频域滤波</span></h2>
<p>从某条曲线中除去一些特定的频率成份,这在工程上称为“<strong>滤波</strong>”。</p>
<p>含噪信号是高能信号与低能噪声叠加的信号,可以通过傅里叶变换的频域滤波实现降噪。</p>
<p>通过FFT使含噪信号转换为含噪频谱,去除低能噪声,留下高能频谱后再通过IFFT留下高能信号。</p>
<p>案例:基于傅里叶变换的频域滤波为音频文件去除噪声(noiseed.wav数据集地址)。</p>
<p>  1、读取音频文件,获取音频文件基本信息:采样个数,采样周期,与每个采样的声音信号值。绘制音频时域的:时间/位移图像</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> numpy as np
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> numpy.fft as nf
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> scipy.io.wavfile as wf
</span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> matplotlib.pyplot as plt

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 读取音频文件</span>
sample_rate, noised_sigs = wf.read(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">./da_data/noised.wav</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(sample_rate)<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> sample_rate:采样率44100</span>
<span style="color: rgba(0, 0, 255, 1)">print</span>(noised_sigs.shape)    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> noised_sigs:存储音频中每个采样点的采样位移(220500,)</span>
times = np.arange(noised_sigs.size) /<span style="color: rgba(0, 0, 0, 1)"> sample_rate

plt.figure(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Filter</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.subplot(</span>221<span style="color: rgba(0, 0, 0, 1)">)
plt.title(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Time Domain</span><span style="color: rgba(128, 0, 0, 1)">'</span>, fontsize=16<span style="color: rgba(0, 0, 0, 1)">)
plt.ylabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Signal</span><span style="color: rgba(128, 0, 0, 1)">'</span>, fontsize=12<span style="color: rgba(0, 0, 0, 1)">)
plt.tick_params(labelsize</span>=10<span style="color: rgba(0, 0, 0, 1)">)
plt.grid(linestyle</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.plot(times[:</span>178], noised_sigs[:178], c=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">orangered</span><span style="color: rgba(128, 0, 0, 1)">'</span>, label=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Noised</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.legend()</span></pre>
</div>
<p>&nbsp;<img src="https://img2018.cnblogs.com/blog/1433301/201909/1433301-20190920162516886-569185403.png" alt="" style="display: block; margin-left: auto; margin-right: auto"></p>
<p>  2、基于傅里叶变换,获取音频频域信息,绘制音频频域的:频率/能量图像</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 傅里叶变换后,绘制频域图像</span>
freqs = nf.fftfreq(times.size, times -<span style="color: rgba(0, 0, 0, 1)"> times)
complex_array </span>=<span style="color: rgba(0, 0, 0, 1)"> nf.fft(noised_sigs)
pows </span>=<span style="color: rgba(0, 0, 0, 1)"> np.abs(complex_array)

plt.subplot(</span>222<span style="color: rgba(0, 0, 0, 1)">)
plt.title(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Frequency Domain</span><span style="color: rgba(128, 0, 0, 1)">'</span>, fontsize=16<span style="color: rgba(0, 0, 0, 1)">)
plt.ylabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Power</span><span style="color: rgba(128, 0, 0, 1)">'</span>, fontsize=12<span style="color: rgba(0, 0, 0, 1)">)
plt.tick_params(labelsize</span>=10<span style="color: rgba(0, 0, 0, 1)">)
plt.grid(linestyle</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 指数增长坐标画图</span>
plt.semilogy(freqs, pows, c=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">limegreen</span><span style="color: rgba(128, 0, 0, 1)">'</span>, label=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Noised</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.legend()</span></pre>
</div>
<p style="text-align: center"><img src="https://img2018.cnblogs.com/blog/1433301/201909/1433301-20190920162547116-786582203.png" alt=""></p>
<p>  3、将低频噪声去除后绘制音频频域的:频率/能量图像</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 寻找能量最大的频率值</span>
fund_freq =<span style="color: rgba(0, 0, 0, 1)"> freqs
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> where函数寻找那些需要抹掉的复数的索引</span>
noised_indices = np.where(freqs !=<span style="color: rgba(0, 0, 0, 1)"> fund_freq)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 复制一个复数数组的副本,避免污染原始数据</span>
filter_complex_array =<span style="color: rgba(0, 0, 0, 1)"> complex_array.copy()
filter_complex_array </span>=<span style="color: rgba(0, 0, 0, 1)"> 0
filter_pows </span>=<span style="color: rgba(0, 0, 0, 1)"> np.abs(filter_complex_array)

plt.subplot(</span>224<span style="color: rgba(0, 0, 0, 1)">)
plt.xlabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Frequency</span><span style="color: rgba(128, 0, 0, 1)">'</span>, fontsize=12<span style="color: rgba(0, 0, 0, 1)">)
plt.ylabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Power</span><span style="color: rgba(128, 0, 0, 1)">'</span>, fontsize=12<span style="color: rgba(0, 0, 0, 1)">)
plt.tick_params(labelsize</span>=10<span style="color: rgba(0, 0, 0, 1)">)
plt.grid(linestyle</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.plot(freqs, filter_pows, c=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">dodgerblue</span><span style="color: rgba(128, 0, 0, 1)">'</span>, label=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Filter</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.legend()</span></pre>
</div>
<p><img src="https://img2018.cnblogs.com/blog/1433301/201909/1433301-20190920162631676-1555682794.png" alt="" style="display: block; margin-left: auto; margin-right: auto"></p>
<p>  4、基于逆向傅里叶变换,生成新的音频信号,绘制音频时域的:时间/位移图像</p>
<div class="cnblogs_code">
<pre>filter_sigs =<span style="color: rgba(0, 0, 0, 1)"> nf.ifft(filter_complex_array).real
plt.subplot(</span>223<span style="color: rgba(0, 0, 0, 1)">)
plt.xlabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Time</span><span style="color: rgba(128, 0, 0, 1)">'</span>, fontsize=12<span style="color: rgba(0, 0, 0, 1)">)
plt.ylabel(</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Signal</span><span style="color: rgba(128, 0, 0, 1)">'</span>, fontsize=12<span style="color: rgba(0, 0, 0, 1)">)
plt.tick_params(labelsize</span>=10<span style="color: rgba(0, 0, 0, 1)">)
plt.grid(linestyle</span>=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">:</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.plot(times[:</span>178], filter_sigs[:178], c=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hotpink</span><span style="color: rgba(128, 0, 0, 1)">'</span>, label=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">Filter</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
plt.legend()</span></pre>
</div>
<p><img src="https://img2018.cnblogs.com/blog/1433301/201909/1433301-20190920162656136-593011515.png" alt="" style="display: block; margin-left: auto; margin-right: auto"></p>
<p>  5、重新生成音频文件</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 生成音频文件</span>
wf.write(<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">./da_data/filter.wav</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">, sample_rate, filter_sigs)
plt.show()</span></pre>
</div>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2>离散傅里叶变换 (DFT)</h2>
<p>  离散傅里叶变换(DFT)对有限长时域离散信号的频谱进行等间隔采样,频域函数被离散化了,便于信号的计算机处理。DFT的运算量太大,FFT是离散傅里叶变换的快速算法。</p>
<p>  说白了FFT和DFT它俩就是一个东东,只不过复杂度不同,</p>
<p>  有时候我们能够看到N点傅里叶变换,我个人理解是这个N点是信号前面N个连续的数值,即N点FFT意思就是截取前面N个信号进行FFT,这样就要求我们的前N个采样点必须包含当前信号的一个周期,不然提取的余弦波参数与正确的叠加波的参数相差很大。</p>
<p>  如果在N点FFT的时候,如果这N个采样点不包含一个周期呢?或者说我们的信号压根不是一个周期函数咋办?或者有一段是噪音数据呢?如果用FFT计算,就会对整体结果影响很大,然后就有人想通过局部来逼近整体,跟微积分的思想很像,将信号分成一小段一小段,然后对每一小段做FFT,就跟分段函数似的,无数个分段函数能逼近任意的曲线((⊙o⊙)…应该没错吧),这样每一段都不会互相影响到了。</p>
<h1>二、短时傅里叶变换 (STFT)</h1>
<p>  在短时傅里叶变换过程中,窗的长度决定频谱图的时间分辨率和频率分辨率,窗长越长,截取的信号越长,信号越长,傅里叶变换后频率分辨率越高,时间分辨率越差;相反,窗长越短,截取的信号就越短,频率分辨率越差,时间分辨率越好,也就是说短时傅里叶变换中,时间分辨率和频率分辨率之间不能兼得,应该根据具体需求进行取舍。</p>
<p>计算短时傅里叶变换,需要指定的有:</p>
<ul>
<li>每个窗口的长度:nsc</li>
<li>每相邻两个窗口的重叠率:nov</li>
<li>每个窗口的FFT采样点数:nff</li>
</ul>
<p>可以计算的有:</p>
<ul>
<li>海明窗:w=hamming(nsc, 'periodic')</li>
<li>信号被分成了多少片</li>
<li>短时傅里叶变换:</li>
</ul>
<p><strong>python库librosa实现</strong></p>
<div class="cnblogs_code">
<pre>librosa.stft(y, n_fft=<span style="color: rgba(128, 0, 128, 1)">2048</span>, hop_length=None, win_length=None, window=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hann</span><span style="color: rgba(128, 0, 0, 1)">'</span>, center=True, pad_mode=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">reflect</span><span style="color: rgba(128, 0, 0, 1)">'</span>)</pre>
</div>
<p>短时傅立叶变换(STFT),返回一个复数矩阵使得D(f,t)</p>
<p><strong>参数:</strong></p>
<ul>
<li><strong>y:</strong>音频时间序列</li>
<li><strong><strong>n_fft</strong><span class="classifier-delimiter">:</span></strong><span class="classifier-delimiter">FFT窗口大小,n_fft=hop_length+overlapping</span></li>
<li><strong><strong>hop_length</strong><span class="classifier-delimiter">:</span></strong><span class="classifier-delimiter">帧移,如果未指定,则默认win_length / 4。</span></li>
<li><strong><strong>win_length</strong><span class="classifier-delimiter">:</span></strong>每一帧音频都由window()加窗。窗长win_length,然后用零填充以匹配N_FFT。默认<code class="docutils literal notranslate"><span class="pre">win_length<span class="pre">=<span class="pre">n_fft</span></span></span></code>。</li>
<li><strong>window</strong>:字符串,元组,数字,函数 shape =(n_fft, )
<ul>
<li>窗口(字符串,元组或数字);</li>
<li>窗函数,例如<code>scipy.signal.hanning</code></li>
<li>长度为n_fft的向量或数组</li>
</ul>
</li>
<li><strong><strong>center</strong>:bool</strong>
<ul>
<li>如果为True,则填充信号y,以使帧&nbsp;D [:, t]以y 为中心。</li>
<li>如果为False,则D [:, t]从y 开始</li>
</ul>
</li>
<li><strong><strong>dtype</strong><span class="classifier-delimiter">:</span></strong>D的复数值类型。默认值为64-bit com<span class="classifier-delimiter">plex复数</span></li>
<li><strong><strong>pad_mode</strong><span class="classifier-delimiter">:</span></strong>如果center = True,则在信号的边缘使用填充模式。默认情况下,STFT使用reflection padding。</li>
</ul>
<p><strong>返回:</strong></p>
<ul>
<li>STFT矩阵D,<span class="classifier-delimiter">shape =(1 + $\frac{n_{fft} }{2}$,t)</span></li>
</ul>
<div class="cnblogs_code">
<pre>librosa.magphase(D, power=1)</pre>
</div>
<p>将复值频谱D分离成其幅度(S)和相位(P)</p>
<p><strong>参数</strong>:</p>
<ul>
<li><strong>D</strong>:复值谱图,np.ndarray </li>
<li><strong>power</strong>:幅度谱图的指数,例如,1代表能量,2代表功率,等等。</li>
</ul>
<p><strong>返回</strong>:</p>
<ul>
<li><strong>D_mag&nbsp;</strong><span class="classifier-delimiter">:D的幅值,<span class="classifier">np.ndarray </span></span></li>
<li><strong>D_phase&nbsp;</strong><span class="classifier-delimiter">:D的相位,<span class="classifier">np.ndarray ,</span></span><em class="xref py py-obj">exp(1.j * phi)</em>其中<em class="xref py py-obj">phi</em>是<em class="xref py py-obj">D</em>的相位</li>
</ul>
<div class="cnblogs_code">
<pre>y, _ = librosa.load(<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">p225_002.wav</span><span style="color: rgba(128, 0, 0, 1)">"</span>, sr=16000<span style="color: rgba(0, 0, 0, 1)">)

D </span>= librosa.stft(y, n_fft=2048, hop_length=None, win_length=None, window=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">hann</span><span style="color: rgba(128, 0, 0, 1)">'</span>, center=True, pad_mode=<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">reflect</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">print</span>(D.shape)    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> (1025, 127)</span>

<span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 将复值频谱D分离成其幅度(S)和相位(P)的部件</span>
magnitude, phase = librosa.magphase(D, power=1<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> magnitude      # 赋值 (1025, 127)</span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> phase.shape    # 相位 (1025, 127) </span>
<span style="color: rgba(0, 0, 0, 1)">
angle </span>= np.angle(phase)   <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 获取相角(以弧度为单位)</span></pre>
</div>
<p>&nbsp;</p>
<p><strong>tensorflow实现</strong></p>
<p>一句话实现分帧、加窗、STFT变换</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> .batch_size and signal_length 可能会不知道</span>
signals =<span style="color: rgba(0, 0, 0, 1)"> tf.placeholder(tf.float32, )

</span><span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> `stfts` 短时傅里叶变换:就是对信号中每一帧信号进行傅里叶变换 </span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> shape is </span><span style="color: rgba(0, 128, 0, 1)">
#</span><span style="color: rgba(0, 128, 0, 1)"> 其中 fft_unique_bins = fft_length // 2 + 1 = 513.</span>
stfts = tf.contrib.signal.stft(signals, frame_length=1024, frame_step=512<span style="color: rgba(0, 0, 0, 1)">,
                                                            fft_length</span>=1024)</pre>
</div>
<p>wlen:窗长</p>
<p>frame_length是信号中帧的长度</p>
<p>frame_step是帧移</p>
<p>fft_length:做fft变换的长度,或一种说话:fft变换所取得N点数,在有些地方也表示为NFFT。</p>
<p>注意:FFT的长度必须大于或者等于win的长度或者帧长。以获得更高的频域分辨率</p>
<p>FFT后的分辨率(频率的间隔)为fs/NFFT。当NFFT&gt;wlen时就是在数据补零后做FFT,做的FFT得到的频谱等于以wlen长数据FFT的频谱中内插。</p>
<p><strong>numpy库实现</strong></p>
<p>上面的一行代码相当于下面一大段代码</p>
<div class="cnblogs_code"><img src="https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif" alt="" id="code_img_closed_8e88fdd8-8085-4214-b3d6-5cc65ec933c4" class="code_img_closed"><img src="https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif" alt="" id="code_img_opened_8e88fdd8-8085-4214-b3d6-5cc65ec933c4" class="code_img_opened" style="display: none">
<div id="cnblogs_code_open_8e88fdd8-8085-4214-b3d6-5cc65ec933c4" class="cnblogs_code_hide">
<pre><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> wav_to_frame(wave_data, win_len, win_shift):
    </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
    进行分帧操作
    :param wave_data: 原始的数据
    :param win_len: 滑动窗长
    :param win_shift: 滑动间隔
    :return: 分帧之后的结果,输出一个帧矩阵
    </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(0, 0, 0, 1)">
    num_frames </span>= (len(wave_data) - win_len) // win_shift + 1<span style="color: rgba(0, 0, 0, 1)">
    results </span>=<span style="color: rgba(0, 0, 0, 1)"> []
    </span><span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> range(num_frames):
      results.append(wave_data)
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> np.array(results)

</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> spectrum_power(frames, NFFT):
    </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">
    计算每一帧傅立叶变换以后的功率谱
    参数说明:
    frames:audio2frame函数计算出来的帧矩阵
    NFFT:FFT的大小
    </span><span style="color: rgba(128, 0, 0, 1)">"""</span>
    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 功率谱等于每一点的幅度平方/NFFT</span>
    <span style="color: rgba(0, 0, 255, 1)">return</span> 1.0/NFFT *<span style="color: rgba(0, 0, 0, 1)"> np.square(spectrum_magnitude(frames, NFFT))

</span><span style="color: rgba(0, 0, 255, 1)">def</span><span style="color: rgba(0, 0, 0, 1)"> spectrum_magnitude(frames, NFFT):
    </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(128, 0, 0, 1)">计算每一帧经过FFT变幻以后的频谱的幅度,若frames的大小为N*L,则返回矩阵的大小为N*NFFT
    参数:
    frames:即audio2frame函数中的返回值矩阵,帧矩阵
    NFFT:FFT变换的数组大小,如果帧长度小于NFFT,则帧的其余部分用0填充铺满
    </span><span style="color: rgba(128, 0, 0, 1)">"""</span><span style="color: rgba(0, 0, 0, 1)">
    complex_spectrum </span>= np.fft.rfft(frames, NFFT)    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 对frames进行FFT变换</span>
    <span style="color: rgba(0, 128, 0, 1)">#</span><span style="color: rgba(0, 128, 0, 1)"> 返回频谱的幅度值</span>
    <span style="color: rgba(0, 0, 255, 1)">return</span> np.absolute(complex_spectrum)</pre>
</div>
<span class="cnblogs_code_collapse">View Code</span></div>
<p>&nbsp;</p>
<h1>三、frequency bin</h1>
<p>在读paper的时候总是会遇到 <strong>frequency bin</strong>&nbsp;(频率窗口)这个词,</p>
<p>  <span style="color: rgba(0, 128, 128, 1)"><strong>frequency bin</strong></span>&nbsp;是指:raw data 经过FFT后得到的频谱图<span style="color: rgba(128, 128, 128, 1)">(频域率)</span>中,<span style="color: rgba(255, 0, 0, 1)"><strong>频率轴的频率间隔</strong></span><span style="color: rgba(128, 128, 128, 1)">或分辨率</span>,通常取决采样率和采样点。</p>
<p>$$frequency \quad bin=\frac{采样率}{采样点数}=\frac{f_{sample}}{N_{recode}}$$</p>
<p>  $N_{recode}$&nbsp; 是信号在时域的采样点数,频谱中的频率点<span style="color: rgba(128, 128, 128, 1)">或线</span>的数量为$\frac{N_{recode}}{2}$&nbsp; <span style="color: rgba(128, 128, 128, 1)">(奈奎斯特采样定理)</span></p>
<p>  频谱的第一个频点始终为直流(频率=0),最后一个频点为$\frac{f_{sample}}{2}-\frac{f_{sample}}{N_{recode}}$&nbsp; 。<span style="color: rgba(255, 102, 0, 1)"><strong>频点采用相等的间隔,这间隔通常用<strong>frequency bin</strong><span style="color: rgba(255, 102, 0, 1)">(<strong>频率窗口</strong>)</span>或FFT bin表示</strong></span>。</p>
<p>例子1:我们可以作用82MHz的采样频率,取得8200个数据记录,frequency bin$=\frac{82000000}{8200}=10000=10kHz$。</p>
<p>例子2:frequency bin是频率域中采样点之间的间隔。例如,如果采样率为100赫兹,FFT为100个点,frequency bin=1,则在[0 100)赫兹之间有100个点。因此,您将整个100赫兹范围划分为100个间隔,如0-1赫兹、1-2赫兹等。每一个如此小的间隔,比如0-1Hz,都是一个frequency bin<span style="color: rgba(128, 128, 128, 1)">(频率箱)</span>。</p>
<h1>参考</h1>
<p>知乎Heinrich博主文章——傅里叶分析之掐死教程</p>
<p class="title-article">【音频处理】离散傅里叶变换</p>
<p class="title-article">【音频处理】短时傅里叶变换</p><br><br>
来源:https://www.cnblogs.com/LXP-Never/p/11558302.html
頁: [1]
查看完整版本: 快速傅里叶变换及python代码实现