前言

近期我们的 ADC 系列越来越多涉及 “滤波器”、“FFT” 等概念,这让我觉得可以重新了解一下 “数字信号处理” 。虽然我在大学的时候学过,但一晃 15 年过去了,绝大部分内容我已经忘得差不多了。

数字信号处理应该是个特别 “酷” 的话题,而不是课本上那些无聊的公式。比如,很多与传感器适配的 ASIC ,内部就拥有一颗 DSP;还有 SDR 处理器,内部也有用于信号调制解调的 DSP。正是这些有着特定用途的 DSP 加持,让芯片能在市场上彰显差异。

从实现角度,数字信号处理经常会用到 Python 和 Matlab 两种工具。我打算主要使用前者,因为 Python 更开放,开源例程也很多,还能很方便地和 AI / Edge Computing 等结合(虽然我现在还不知道怎么做,让我们来一步步了解)。

本文是“数字信号处理”系列第一篇,介绍开发工具和环境,然后用 Python 生成一个 Sine 波形,保存为 Wav 文件,再用现成的音频软件播放、查看波形和频谱(其思路和代码来自于国外博主)。

按惯例声明一下:我的解释不一定是对的,还可能存在错误,有时我自己也不知道在说什么。所以仅供参考,欢迎讨论。

开发工具和环境

Python 用于数字信号处理主要用到 NumPy、SciPy 和 Matplotlib 三个库:

  • NumPy (Numeric Python)是 Python 进行科学计算的基础,它支持多维数组,以及处理这些数组的函数,比如,数字信号处理中的卷积、相关等基础运算。

  • SciPy(Scientific Python) 是以 Numpy 为基础,构建更专业、复杂的计算,比如,数字信号处理中的滤波、频谱、插值等。

  • Matplotlib 是一个绘图库,对时域、频谱图形都可以绘制,可以让我们清晰观察和理解信号。

此外,还需要一个开发环境,这里使用 Spyder,它是专门为 Python 科学计算开发的集成开发环境(IDE),我觉得上手比较简单。当然你也可以用其他的,如 Jupyter Notebook、Visual Studio 等。

Spyder 官网和下载安装见参考资料 [1],在 Linux 系统上它似乎默认就带有 NumPy、SciPy 和 Matplotlib 三个库,如果没有的话,可以用如下方式安装:

1
2
3
python -m pip install numpy
python -m pip install scipy
python -m pip install matplotlib

下图是安装完 Spyder,并用 Matplotlib 绘制一个“火狐”图形的效果,这个示例的代码链接见参考资料 [2]。下载代码后,导入运行即可,细节步骤省了:

图1 Spyder 运行 Matplotlib 官方案例 firefox.py

图1 Spyder 运行 Matplotlib 官方案例 firefox.py

总之,不错、挺酷。

生成 Sine 波形

然后是本文的主题,用 Python 生成一个 Sine 波形,保存为 Wav 文件。整个创作思路和代码见参考资料 [3],我对代码没做什么改动,作者是 Shantnu Tiwari ,撰写过多本 Python 书籍。

作者的代码托管在 Github,国内访问不太方便,为便于下载,我在 Gitee 上同步了一下,见文末链接。

从 Spyder 导入代码,运行后能看到 Sine 波形,并在目录下生成 “test.wav” 文件:

图2 Spyder 运行 create_wave.py

图2 Spyder 运行 create_wave.py

图3 生成 test.wav 文件

图3 生成 test.wav 文件

整个代码不到 40 行,第 7 行到第 13 行展示了 Sine 波形的生成方式:

1
2
3
4
5
6
7
# frequency is the number of times a wave repeats a second
frequency = 1000
num_samples = 48000
# The sampling rate of the analog to digital convert
sampling_rate = 48000.0

sine_wave = [np.sin(2 * np.pi * frequency * x/sampling_rate) for x in range(num_samples)]

这段代码生成的是频率为 1000 Hz,采样率为 48000 Hz,采样点数 48000 个(也就是 1秒钟时长)的 Sine 波形,幅度默认是 1。

我们与经典的 Sine 数学公式对比一下:

1
y(t) = A * sin(2 * pi * f * t)

可以发现,代码是将数学公式中的 “ t ” 替换为 “ x/sampling_rate ”,因此,实际的 Sine 波形是一组离散的数值。

代码中第 16 行到第 18 行是绘制 Sine 波形。

代码中第 20 行到第 33 行是储存为 Wav 文件。Wav 文件有一些编码要求,如 幅度为有符号 16-bit 整形、压缩类型、通道数量等。其中,幅度与音量有关,作者将 Sine 波形幅度设置为 16-bit(2^15 – 1 = 32767)的大致一半,即 16000(第 26 行) 。

其他详情可查阅代码及函数的使用说明。

Audacity 音频软件

有了 Wav 文件后,就能用音频软件播放了,这样我们可以听到 “1000 Hz” 的声音。

作者使用了 Audacity(参考资料[4]),这是个开源领域著名的音频软件,我作为 Linux 用户很早就用过,但不知道还能有如下玩法。

第一、查看时域波形:

从 Audacity 导入 Wav 文件,缩放时间轴,看到 Sine 波形,像示波器一样:

图4 Audacity 查看时域波形

图4 Audacity 查看时域波形

第二、查看频谱图:

菜单上点击 Select -> All,然后 Analyze -> Plot Spectrum,看到频谱图:

图5 Audacity 查看频谱图

图5 Audacity 查看频谱图

图中,频谱的中心频率就是我们设定的 1000 Hz。

至于为何整个频谱像正态分布,而不是单独 1000 Hz 上的一根线?这是频谱泄露(Spectrum Leakage)现象,等我们介绍 DFT 时再展开说明。

总结

本文介绍了 Python 用于数字信号处理的开发工具和环境,然后,用 Python 生成一个 Sine 波形,保存为 Wav 文件,再用 Audacity 音频软件播放、查看波形和频谱。

原作者提供的代码在 Github 上,为便于国内下载,我将其同步至 Gitee,请见文末“相关代码”链接,你可以下载运行,尝试改变频率、幅度等参数看看效果。

参考资料

  1. https://www.spyder-ide.org/
  2. https://matplotlib.org/stable/gallery/showcase/firefox.html
  3. https://new.pythonforengineers.com/blog/audio-and-digital-signal-processingdsp-in-python/
  4. https://www.audacityteam.org/

相关代码(Gitee)

https://gitee.com/gilbertjuly/digital-signal-processing-code/tree/master/01_create_wave


欢迎关注我的微信公众号“疯狂的运放”,及时收到最新的推文。