python傅里叶变换 信号处理 序列_零、信号处理基础知识快速介绍(前)

3ab86b67d69adf7ddb430ef9f8b6dea8.png
Tux ZZ:零、信号处理基础知识快速介绍(后)​zhuanlan.zhihu.com

这篇文章主要讲述以下内容:

前:

  1. 声音的时域表示
  2. 正弦余弦信号
  3. 声音的频域表示
  4. 相关性、DFT、补零

后:

  1. 窗函数、STFT
  2. 滤波器
  1. 声音的时域表示

  如同物理学中各种一样,声音也是一种波。而声波在各个时刻的振幅按时间顺序记录下来,便是声音的时域表示。通常来说,我们说声音的波形便是指的声音的时域表示。

我们可以使用大多数音频处理软件查看声音的波形,比如Audacity或者Adobe Audition。在这里我们使用Audacity,因为它功能够用,而且是免费的。

  安装好Audacity后,我们打开一个音频文件,便直接可以看到声音的波形,横着为时间轴,竖着为振幅轴,振幅越偏离0点表示振幅越大。

a614d09990bdffea1ed19c88425b8c93.png
打开了音频文件的Audacity界面

  同样的,我们可以在Python中自己加载wav文件并绘制出波形图。

import 

  使用Python 3运行之:

af2ccc0986ee5d1aa799eb136844436f.png
运行结果

2. 正弦余弦信号

在Audacity,我们可以将鼠标放置在波形窗口后通过 Ctrl+滚轮上滚 来在时间维度放大波形,或将鼠标放置在波形窗口的时间轴后通过 Ctrl+滚轮上滚 在振幅轴上放大波形。如此一来我们便可以仔细观察声波的形状了。在很多音乐中(尤其是乐器单一的音乐,比如纯人声),放大到足够大小时你会发现,波形中出现了一些周期变化的形状(如图)。

fa40181fb1be543e245575a6ffa7d6be.png
红线标注间的波形呈周期性出现

  看到这上下波动的形状,是不是想到了物理课上讲波时经常出现的 正弦/余弦函数 了呢?没错,离散的声音信号 都是可以由有限个 正弦/余弦信号 叠加得到的,这个叠加和物理中波的叠加没什么区别。公式可以表示为

  我们可以在Audacity里生成正弦。

450672f9a044ea9f6efd39a6a3f6e011.png
生成正弦

c5d19ff192b43b821239aaadadc94aa3.png
一个440Hz频率,0.8振幅的正弦

  我们还可以增加多个轨道,生成出不同频率的正弦,然后混缩到一条轨道(相当于叠加)。

c1f3e10cc44433e0dbe2a43b69bb7ac4.png
三个正弦,440Hz、880Hz、1320Hz,振幅均为0.25

  是不是和之前音乐中的波形有几分相似之处呢?

  我们也可以通过Python生成:

import 

e01e5e70762e7e452b7db7cf89b60275.png
运行结果

注意:播放时振幅最大处不应超出[-1.0, 1.0]的范围,不然会被削成[-1.0, 1.0],导致破音。

注意:我们生成的 正弦/余弦信号 的频率是有限制的,它不应该超过1/2采样率大小。因为根据采样定理,只有采样率1/2倍以下频率的信号才能被完美恢复,这个最大的频率即为Nyquist频率。超出最大范围的部分不但无法表示,还会造成混叠,即高于采样频率一半的频率成分将被重建成低于采样频率一半的信号。

3. 声音的频域表示

  自然界的声音都可以分解成简单的 正弦/余弦。但是在上面的例子中,即使只有三个正弦叠加起来,我们用肉眼也难以分辨出那三个成分。这时我们可以使用 DFT(离散傅里叶变换)这种方法将信号从时域变换到频域,这样我们就可以轻松看出来其中不同的频率成分了。

  在Audacity中,我们可以划选一段信号,然后点击 分析->频率分析 来查看这段信号的傅里叶变换。对之前我们生成的440Hz+880Hz+1320Hz信号,它的频谱可能是这样的:

d984a2c8eaf8e3c0b4f0fc6a656364cf.png
Audacity频谱分析

  同样,我们可以在Python中使用numpy提供的FFT(快速傅里叶变换,你可以理解成DFT的快速版)函数实现类似的效果:

import 

2c819472afdf42e03d043e2b43f17624.png
运行结果

  可以看到有三个振幅0.25的峰,正是我们生成的信号。和Audacity中不同是因为Audacity中振幅的单位是分贝,换算公式为

。分贝是查看频谱最常用的单位,因为其大小关系与人类感知相近。

  你可能对DFT输出的形式有点好奇:为什么它是一个复数?因为根据欧拉公式,三角函数可以转换成复指数函数的形式,即

,可以表示一个任意初相位的余弦信号。而这个复数的模即为余弦的振幅,夹角即为余弦的初相位。

  我们将一个n点的实数信号输入进DFT,其会返回一个n // 2 + 1点的输出。其中每个点代表一个余弦信号分量,从0Hz直到Nyquist频率,我们称每一个数据点叫一个bin(桶)。比如我们将一个采样率为1000Hz,长度为100采样的信号输入进去,DFT输出的每个bin对应的频率即为0Hz, 10Hz, 20Hz, ..., 500Hz。对于离散实数信号来说,n // 2 + 1个bin足以表示原来的信号。而对于长度为n的复数输入信号,则需要n个bin才能表示,这里我们不过多讨论复数输入,因为在语音处理中它并不常用。

4. 相关性、DFT、补零

我们在前面介绍了如何使用DFT(实际用的是FFT,DFT的快速版本),但是DFT是如何实现的呢?让我们先讲讲信号的 相关性

相关性 顾名思义,就是两个信号的相似程度(实际定义更复杂些)。计算相关性的方法为

,离散情况下也就是把俩信号同时间每个采样互相乘起来最后求和。对两个完全一样的周期信号来说,他们的相关性为1。而对于两个不同的白噪声,他们的相关性趋近于0。如果信号有截断,只有整周期截断才能准确计算出相关性。
import 

  更前面我们提到,DFT输出结果中每个桶都是余弦信号分量,任意相位的余弦信号又可以拆成一个正弦和一个余弦的叠加。现在我们又提到,用相关性的方法可以求两个信号的相似程度。于是自然可以想到,可以将原始信号与每个桶对应频率的正弦信号和余弦信号求相关性,便可以直接得到DFT输出复数的实部和虚部。

import 

57b8295068de6fc1cd673038dea22a6e.png
运行结果

  与此同时,不知你是否注意到一个问题:DFT输出结每个桶之间隔着的距离是和信号输入长度相关的,如果信号很短,桶之间距离就很远,频率分辨率就会变得很低。在这种情况下,你可以试试将输入信号末尾加一定长度的0,这样做相当于将频域结果进行Sinc插值,并没有真的提高频率分辨率。但是很多时候它还是能为我们提供很大帮助。

import 

18b789345e38bcd1825111cc527e1037.png
补零后(橘色)和补零前(蓝色)对比

  观察补零后(橘色)和补零前(蓝色)的DFT结果,很明显在补零后的信号上我们能更准确更轻松地找到峰。

Tux ZZ:零、信号处理基础知识快速介绍(后)​zhuanlan.zhihu.com
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值