python作傅里叶变换

傅里叶变换(fft)

  法国科学家傅里叶提出,任何一条周期曲线,不管多么跳跃或不规则,都能表示成一组光滑正弦曲线叠加之和。傅里叶变换便是把一条不规则的曲线拆解成一组光滑正弦曲线的过程。git

  傅里叶变换的目的是将时域(即时间域)上的信号转变为频域(即频率域)上的信号,随着域的变换,对同一个事物的了解角度也就随之改变,所以在时域中某些很差处理的地方,在频域就能够较为简单的处理。这就能够大量减小处理信号存储量。github

例如:弹钢琴数组

假设有一时间域函数:y = f(x),根据傅里叶的理论它能够被分解为一系列正弦函数的叠加,他们的振幅A,频率ω或初相位φ不一样:函数

$$y = A_1sin(\omega_1x+\phi_1) +  A_2sin(\omega_2x+\phi_2) +  A_2sin(\omega_2x+\phi_2) + R$$spa

因此傅里叶变换能够把一个比较复杂的函数转换为多个简单函数的叠加,看问题的角度也从时间域转到了频率域,有些的问题处理起来就会比较简单。code

傅里叶变换相关函数

freqs = np.fft.fft.fftfreq(采样数量, 采样周期)  经过采样数与采样周期求得傅里叶变换分解所得数组的频率序列blog

np.fft.fft.fft(原序列)  原函数值的序列通过快速傅里叶变换获得一个复数数组,复数的模表明的是振幅,复数的辐角表明初相位索引

np.fft.fft.ifft(复数序列)  复数数组 通过逆向傅里叶变换获得合成的函数值数组ip

案例:针对合成波作快速傅里叶变换,获得分解波数组的频率、振幅、初相位数组,并绘制频域图像。ci

import numpy as np
import matplotlib.pyplot as plt
import numpy.fft as fft

x = np.linspace(-2 * np.pi, 2 * np.pi, 1000)

n = 1000
y = np.zeros(x.size)
for i in range(1, n + 1):
    y += 4 * np.pi / (2 * i - 1) * np.sin((2 * i - 1) * x)

complex_array = fft.fft(y)
print(complex_array.shape)  # (1000,) 
print(complex_array.dtype)  # complex128 
print(complex_array[0])  # (-2.1458390619955026e-12+0j)
y_new = fft.ifft(complex_array)

plt.subplot(311)
plt.grid(linestyle=':')
plt.plot(x, y, label='y')  # y是1000个相加后的正弦序列
plt.subplot(312)
plt.plot(x, y_new, label='y_new', color='orangered')  # y是ifft变换后的序列

# 获得分解波的频率序列
freqs = fft.fftfreq(x.size, x[1] - x[0])
# 复数的模为信号的振幅(能量大小)
complex_array = fft.fft(y)
pows = np.abs(complex_array)

plt.subplot(313)
plt.title('Frequency Domain', fontsize=16)
plt.xlabel('Frequency', fontsize=12)
plt.ylabel('Power', fontsize=12)
plt.tick_params(labelsize=10)
plt.grid(linestyle=':')
plt.plot(freqs[freqs > 0], pows[freqs > 0], c='orangered', label='Frequency')
plt.legend()
plt.tight_layout()
plt.show()

基于傅里叶变换的频域滤波

含噪信号是高能信号与低能噪声叠加的信号,能够经过傅里叶变换的频域滤波实现降噪。

经过FFT使含噪信号转换为含噪频谱,去除低能噪声,留下高能频谱后再经过IFFT留下高能信号。

案例:基于傅里叶变换的频域滤波为音频文件去除噪声(noiseed.wav数据集地址)。

  一、读取音频文件,获取音频文件基本信息:采样个数,采样周期,与每一个采样的声音信号值。绘制音频时域的:时间/位移图像

import numpy as np
import numpy.fft as nf
import scipy.io.wavfile as wf
import matplotlib.pyplot as plt

# 读取音频文件
sample_rate, noised_sigs = wf.read('./da_data/noised.wav')
print(sample_rate)  # sample_rate:采样率44100
print(noised_sigs.shape)    # noised_sigs:存储音频中每一个采样点的采样位移(220500,)
times = np.arange(noised_sigs.size) / sample_rate

plt.figure('Filter')
plt.subplot(221)
plt.title('Time Domain', fontsize=16)
plt.ylabel('Signal', fontsize=12)
plt.tick_params(labelsize=10)
plt.grid(linestyle=':')
plt.plot(times[:178], noised_sigs[:178], c='orangered', label='Noised')
plt.legend()

 

  二、基于傅里叶变换,获取音频频域信息,绘制音频频域的:频率/能量图像

# 傅里叶变换后,绘制频域图像
freqs = nf.fftfreq(times.size, times[1] - times[0])
complex_array = nf.fft(noised_sigs)
pows = np.abs(complex_array)

plt.subplot(222)
plt.title('Frequency Domain', fontsize=16)
plt.ylabel('Power', fontsize=12)
plt.tick_params(labelsize=10)
plt.grid(linestyle=':')
# 指数增加坐标画图
plt.semilogy(freqs[freqs > 0], pows[freqs > 0], c='limegreen', label='Noised')
plt.legend()

  三、将低频噪声去除后绘制音频频域的:频率/能量图像

# 寻找能量最大的频率值
fund_freq = freqs[pows.argmax()]
# where函数寻找那些须要抹掉的复数的索引
noised_indices = np.where(freqs != fund_freq)
# 复制一个复数数组的副本,避免污染原始数据
filter_complex_array = complex_array.copy()
filter_complex_array[noised_indices] = 0
filter_pows = np.abs(filter_complex_array)

plt.subplot(224)
plt.xlabel('Frequency', fontsize=12)
plt.ylabel('Power', fontsize=12)
plt.tick_params(labelsize=10)
plt.grid(linestyle=':')
plt.plot(freqs[freqs >= 0], filter_pows[freqs >= 0], c='dodgerblue', label='Filter')
plt.legend()

  四、基于逆向傅里叶变换,生成新的音频信号,绘制音频时域的:时间/位移图像

filter_sigs = nf.ifft(filter_complex_array).real
plt.subplot(223)
plt.xlabel('Time', fontsize=12)
plt.ylabel('Signal', fontsize=12)
plt.tick_params(labelsize=10)
plt.grid(linestyle=':')
plt.plot(times[:178], filter_sigs[:178], c='hotpink', label='Filter')
plt.legend()

  五、从新生成音频文件

# 生成音频文件
wf.write('./da_data/filter.wav', sample_rate, filter_sigs)
plt.show()
相关文章
相关标签/搜索