第一篇 数字音频处理系统的基本原理
- [导读]
- 每个板子都能歌唱
写在前面:
21ic打算携手资(tu)深(ding)直男癌晚期工程师zhanzr21,来给大家讲一讲嵌入式系统与音频处理的故事。
关于zhanzr21:
曾经混迹于两岸三地,摸爬滚打在前端后端,搞过学术上过班。现在创业中,欢迎各种撩
点击链接加入群【嵌入式音频信号处理】:https://jq.qq.com/?_wv=1027&k=45wk8Ks
嵌入式音频专用资料代码分享:https://pan.baidu.com/s/1dFh5pWd
本期活动地址:https://bbs.21ic.com/icview-1698510-1-1.html
1.声音
从物理学的角度来看,声音就是介质中传播的振动.从生理学的角度来看,声音就是听觉神经接收到的脉冲.从工程的角度来看,声音就是连续的电压变化与内存中的一组组变量.人耳朵能感知的声音频率范围为20Hz-20KHz.超出此频率的称之为超声频(波),低于此的称之次声频(波).深究声音的物理学,生理学,心理学的属性不是本文所能涵盖的内容,如同此系列的前言所言,本文只从工程的角度来理解声音.在这个角度所理解的声音也称之为音频(信号/数据).
对于工程师来说,关心的是音频的录制,处理,混合与再生.这个过程中的音频可以用两个元素来表达:幅度与时间.当然从两个元素衍生出很多其他复合元素,时域的音频也时常转到频率来处理.但是从表面来看,音频的输入与输出都可用幅度与时间这两个元素来表达.
讲得哲学一点,音频就是一个维度上的变化(区别于视频的二维变化,真3D视频的三维变化).数字音频就是这种一维变化的离散近似还原.比如任何编程语言中的一维数组可以表达一段音频.播放两个采样之间的时间间隔决定了音频采样率.下图为一段4bit采样的正弦音频数据.
图 声音的数字存在形式
上图显示的是一种最典型的音频采集的例子,最高幅度的声音强度被表示为1111,最低的为0000.实际中使用的音频采样系统,一般使用8bit至24bit的采样深度.
沈从文先生说过,电影的美不如绘画之美,绘画的美不如文字之美,文字的美不如声音之美,声音之美不如数学之美.这段话说的有点过于玄妙,有的唯心主义的色彩.大致意思是越简单的变化形式越是难以捉磨,也就显得更加神秘迷人.用工程师的语言来翻译就是:低维变化因为形式简单,而使得变化较为二维三维变化更加能表达人类的美学观点.数字音频处理可以说结合了音乐与数学,算是美学中比较高端的内容了.
2.数字音频系统的基本组成
全模拟的音频系统也是存在的,比如传统的AM/FM广播系统属于全模拟的音频系统.这里不多评论.但是只要涉及到复杂一点的数学处理,那么音频必然要先转换为数据才能进行处理.随着计算能力与带宽的飞速发展,现在说的音频系统一般都指的是数字音频系统.这样的系统的特点就是,仅仅在声音的入口出口两个点,音频作为模拟形式存在,中间都作为数字形式被进行滤波,放大,各种处理.一般而言,数字音频系统组成如此:
图 数字音频系统的组成
下面看一看ST的F769-Discovery开发板上的音频系统组成部分:
图 STM32F769-Discovery板子上的音频处理系统组成
[1] LineIn输入接口
[2] LineOut输出接口
[3] 音频Codec(主要相当于DAC,也包含一路ADC)
[4],[5] SPDIF输入输出,一种特殊的信号格式,后面章节中详叙
[6] STM32F769作为处理器,虽然不是专门DSP系列,计算能力也能胜任音频DSP的功能. 也包括DFSDM接口,相当于音频ADC.
[7] SD卡,存储设备
[8] 网口,可以获取数据或者上传数据
[9] MEMS Micphone作为模拟输入源
这个系统的原理图将在后续文章中进行更详细的分析.
3.音频的形状,Play with it!
闲话少说,现在开始动手试着感觉一下音频形状与味道.使用代码来生成一段音频数据,比如生成一段1.5秒的600Hz的正弦波信号(Python 3.5环境):
#!/bin/python
#Example source code for 21ic
#Default runs in Python 3.5 Environment
#Author: zhanzr21
#Description: This Example demonstrates how to generate raw audio data.
#
import os
import math
TEST_SAMPLE_RATE = 22050
TEST_SAMPLE_LEN_SEC = 1.5
TEST_SAMPLE_NUM = int(TEST_SAMPLE_RATE * TEST_SAMPLE_LEN_SEC)
CHAN_NO = 1
AUDIO_HZ = 600
AUDIO_CYCLE = (TEST_SAMPLE_RATE/AUDIO_HZ)
test_amp_gain = 0.75
INT16_MAX = 32767
f=open('test.raw',mode='wb')
for i in range(0, TEST_SAMPLE_NUM):
test_sample = int(INT16_MAX * test_amp_gain * (math.sin(math.pi*2*(i%AUDIO_CYCLE)/AUDIO_CYCLE)))
test_ba = bytearray()
test_ba.append(test_sample&0x00ff)
test_ba.append((test_sample>>8)&0x00ff)
f.write(test_ba)
f.close()
小贴士:最简单的Py thon使用教程
Python的官方版本下载地址: https://www.python.org/downloads/ ,本文 关于一般数据处理使用Python 3开发环境. 这里插播一下简单的实验步骤: 下载安装后,点这里启动IDLE: 新建一个文件: 将这里代码复制进去新打开的窗口,按F5运 行,运行之前提示要保存.建议单独建立一个 Python代码文件夹保存要使用的源代码. Python语言对Tab要求很严格,如果网页上 的代码不能运行请使用后面附带的源代码 使用IDLE打开按F5直接运行.
运行后,相对路径为源代码路径,生成文件在 该目录下找.如果运行有误在第一个窗口中 |
代码比较简单,不多介绍.只提一句,要生成的音频振动频率为AUDIO_HZ, 用频率与采样率来计算AUDIO_CYCLE,每个周期的角度变化为2*Pi.
图 生成的正弦波形状
如果要生成方波呢,把上面代码关键处改成这样就可以了:
test_sample = int(test_amp_gain * (INT16_MAX if ((i%AUDIO_CYCLE)>(AUDIO_CYCLE/2)) else INT16_MIN))
图 生成的方波形状
如果要生成锯齿波,这样改:
test_sample = int(test_amp_gain * (INT16_MIN + (i%AUDIO_CYCLE)*((INT16_MAX-INT16_MIN)/AUDIO_CYCLE)))
图 生成的锯齿波形状
如果要生成三角波,这样改:
test_sample = int(test_amp_gain * (INT16_MIN + (i%AUDIO_CYCLE)*(2*(INT16_MAX-INT16_MIN)/AUDIO_CYCLE)) if ((i%AUDIO_CYCLE)<(AUDIO_CYCLE/2)) else (INT16_MAX - (i%AUDIO_CYCLE)*(2*(INT16_MAX-INT16_MIN)/AUDIO_CYCLE)))
图 生成的三角波形状
上面都是连续信号的还原[非数学意义上的连续信号],要产生那种报警用的嘟嘟嘟信号,还要间歇地加一些空白区,比如要产生200ms的间歇性数据.添加两个定义:
PULSE_HZ = 5
PULSE_CYCLE = (TEST_SAMPLE_RATE/PULSE_HZ)
再将数据生成代码改成:
test_sample = int(INT16_MAX * test_amp_gain * (math.sin(math.pi*2*(i%AUDIO_CYCLE)/AUDIO_CYCLE))) if (0==(i//PULSE_CYCLE)%2) else 0
图 生成的间歇性报警音频形状
上面的波形幅度都是一致的,再看看幅度随着时间衰减与增加的效果.
数据生成代码改成:
test_sample = int(INT16_MAX *
((2*i)/TEST_SAMPLE_NUM if i <(TEST_SAMPLE_NUM//2) else (2-(2*i)/TEST_SAMPLE_NUM)) *
(math.sin(math.pi*2*(i%AUDIO_CYCLE)/AUDIO_CYCLE)))
图 生成的幅度先增强后减弱的正弦音频形状(正弦要拉长时间轴才看得出)
当然还可以生成各种形状,这里就留给大家发挥想象力了.比如将生成数据那一行改成这样:
test_sample = random.randint(INT16_MIN, INT16_MAX)
会生成怎样的波形呢? 留给大家做实验.
这里顺便再提一下,本文所有代码都会有附件提供以便读者方便实验.一般数据处理性质的代码为python代码,复杂的数据处理为Matlab/Octave代码,有必要还会提供C/C++代码.嵌入式系统的将会给出硬件原理图与配套代码.
这个生成的test.raw文件的大小为66150字节.是这么计算的:
raw_file_size = 采样率 * 声道数 * (声道位宽/8) * 音频持续长度
看看上面的代码就知道: 我们定义的采样率 = 22050, 声道为单声道, 位宽为16bit, 持续长度为1.5秒.
这里称之为raw文件,意思为原始格式,也有称为binaryx文件的. 对于这种数据,生成者与使用者都要知道数据的含义才行.和嵌入式开发中用来烧录的binary文件是一个道理,事实上后面的章节中会将此文件直接烧录到板子上进行播放.我们这里可以试着使用烧写工具Jlink打开这个文件:
图 Jlink打开生成的原始文件test.raw
事实上就是现在就可以连接上板子,烧录进去.但是烧在哪个地址,如何使用,将在后面的章节中介绍.
4.音频处理常用软件Audacity简介与导入RAW数据
可能上面给读者贴图的时,就有读者要问了,这个生成的数据怎么弄成波形的.
答案是:用Audacity这个软件显示的.虽然不用它也有很多办法来完成本文的很多任务,但是本文的主旨是讲解音频的处理的数学与信号处理部分的原理,能利用的工具都要利用起来以提高学习与工作的效率.
先简单介绍一下这个软件,因为后面很多地方都要用到它.简单言之,Audacity是个音频的编辑器,就像文本编辑器是写文章的工具一样.Audacity是个跨平台的软件,不管你用什么系统都能用.怎么安装这里就不多讲,网址在这里:
它的功能包括:
· 导入各种音频数据(比如我们刚刚生成的Raw格式,后面要讲的wav,aiff,mp3,ogg,flac,aac等)
· 录音/播放
· 复制,粘贴,剪切(比如大家熟知很多文本编辑器的快捷操作都能使用,Home到一段音频的开始,End到结尾,Ctrl+C, Ctrl+P, Ctrl+X,鼠标拖拉,Ctrl+滑轮缩放等等)
· 格式转换
· 生成某些效果(如延迟,回音,变速,滤波等等)
· 频谱分析
等等等,具体的功能我们用到的时再介绍.
这里先说说怎么导入我们刚刚生成的数据.
图 导入RAW数据
选中刚刚生成的raw文件,弹出选项筐:
图 导入的选项
因为是raw数据,文件中没有任何关于此音频的信息,所以这里要手工填入我们生成数据的参数.填写好之后,点Import就能看到波形了.此时可以各种操作,放大局部,剪切,播放啊.大家可以试试听听同样频率的正弦波,方波,锯齿波效果有何差异.也可以试着改改生成数据代码,试试不同数据的效果.
5.音频的采样率
上面我们代码中设定的采样率为22050,这个频率属于常用的音频采样率之一(虽然很多比较新的声卡已经将最低输入采样率提升到了44100).采样率的意思是对音频信号进行采样的频率,这个频率在音频中间处理与最后播放都要用到.比如作者PC上VIA HD Audio声卡支持的采样率可以在音频设备的驱动中看到:
图 PC音频设备的采样率设置
对于使用内部音频外设的嵌入式设备(如F769的内部SAI),支持的采样率跟CPU使用的PLL设定有关.如果使用外部音频IC,那么支持的采样率跟外部音频IC使用的晶体或者时钟输入有关.关于采样率配置的计算,后面章节中会介绍.
如果将22050的数据以44100的频率播放,那么听到的就是频率快了一倍的效果.相反以11025的频率播放则是频率慢了一倍的效果.在使用Audacity导入的时读者可以试验一下这种效果.读者可能对ADC都有一定的理解,采样率越高,对原信号的还原度也就越高.但是占用的存储与传输带宽也越高.这也是后文要讲的音频压缩的缘由之一.这里我们改改代码,以96K的采样率生成同样频率振动正弦波的音频数据.
在生成正弦波形数据的代码中改这一句:
TEST_SAMPLE_RATE = 96000
当然也把生成文件名改一改,以免覆盖之前的生成结果:
f=open('test_2.raw',mode='wb')
运行,导入,看看两个采样率的波形:
图 22050采样率的波形对比96000采样率的波形
可以看出来下面的形状明显要光滑一点,但是这个例子中两种采样率的数据可能听不出差别来.因为实验音频振动的频率为600Hz,根据Nyquist采样定理,1.2K以上的采样频率已经能够基本还原这个振动了.22050比600高的多,所以听起来差别不大.读者可以改变一下代码,比如生成振动频率为12K的数据,那么这两种采样率生成的效果是可以听出来差别的.
对于比较简单的嵌入式系统来讲,或者早期带宽不富裕的时代,除了压缩的措施,在不怎么重视音频还原度的应用场合(比如电话)采样率与采样深度总是越小越好.比如熟悉通信系统的人可能会听说过"一路PSTN的带宽"这样的术语.这里说的就是一路最简单的电话语音传输带宽:64kbps.这个是8K的采样率8bit的采样宽度得来的带宽需求.8K怎么得来的呢,原来一般人说话声音的主要部分频谱最高只能达到3400Hz,普通人大概是85Hz-1100Hz这个范围.那么根据Nyquist的公式3.4K乘以2再加上一点余量就是8K的采样率.8K的采样率被认为能传输绝大多数的声音内容.这是一段讲话(8K,Signed16bit PCM)的频谱:
图 一段讲话音频的频谱
可以看频谱集中在400Hz至1000Hz左右. 关于频谱的介绍将会放在后面章节.此处提到频谱是为了说明对于采样语音音频,8000Hz一般被认为是最低采样率. 而对于音乐,最低采样率的要求则要高的多.比如所谓的CD音质的采样率为44100Hz, 所谓的DVD音质的采样率为48000Hz.
6.小结
本文介绍了声音的基本知识与用代码生成raw格式的基本音频数据.还介绍了音频编辑软件Audacity以及使用此工具查看原始音频数据.由于是第一篇,笔者对篇幅长短没有什么概念,不知道写的多了还是少了,这一点非常需要读者反馈.
- 本文系21ic原创,未经许可禁止转载!
网友评论
- 联系人:巧克力娃娃
- 邮箱:board@21ic.com
- 我要投稿
-
欢迎入驻,开放投稿
-
人均百万?英伟达中国员工收入曝光! 2024-08-29
-
《黑神话:悟空》玩家硬盘升级攻略:提升游戏体验,畅享3A大作 2024-08-29
-
数睿数据参加《系统与软件工程 低代码开发平台通用技术要求》国家标准编制 2024-08-29
- NRF52810蓝牙数字耳机找人定制
预算:¥30005天前
- 125KW模块式PCS软硬件外包开发
预算:¥1100000015小时前
- 12V汽车启动电源项目BMS设计
预算:¥50000023小时前
- 数据可视化软件 开发
预算:¥5000023小时前
- PLC项目调试修改
预算:¥100001天前
- 起动电机控制器开发
预算:¥1100001天前