ionicons-v5-f

基于Arduino音频信号采样滤波的数字信号处理综合实验

实验题目:基于 Arduino 音频信号采样滤波的数字信号处理综

合实验

1. 课程简要信息

课程名称:《数字信号处理》实验
课程学时:16学时
项目学时:课内 4学时
适用专业:电子信息类
学生年级:大学三年级、第 1学期

2. 实验内容与任务(限 500字,可与“实验过程及要求”合并)

本实验利用 Arduino 采集实际的音频信号,将模拟信号转化为数字信号,然后用 Arduino编程对数字信号进行频谱分析和滤波处理,最后将处理后的信号调制发射出去,由收音机接收并播放出来。在本实验中,学生可以利用低成本的 Arduino 完成音频信号的采样、频谱分析、滤波、调制发射的全流程开发,从而使学生对系统开发、以及数字信号处理和通信原理的基础知识进一步加深理解。

实验内容:

  1. Arduino 通过音频线,将采集到的手机或者电脑播放的音频信号转化为数字信号;
  2. 利用 Arduino 分析音频信号频谱特性,并通过串口传输给电脑显示;
  3. 在 Arduino里面编程对信号进行滤波;
  4. 在 Arduino里面编程对滤波后信号进行AM调制,并发射出去;
  5. 利用收音机接收并播放 Arduino发射的信号。

实验任务:

(1)基础任务:

  1. 在面包板上,搭建 Arduino通过音频线采集音频信号的电路;
  2. 编写 Arduino 采用FFT进行频谱分析的代码;
  3. 编写代码,将频谱分析结果通过串口传输给电脑显示;
  4. 编写 Arduino 滤波的实现代码。

(2)扩展任务:

编写用按钮控制滤波器类型(低通、带通、高通、无滤波)的代码。

3. 实验过程及要求(限 300 字)

  1. 连接电路在面包板上,搭建Arduino 通过音频线采集音频信号的电路。

  2. 频谱分析对AD采样信号进行 FFT 处理获得频谱分析结果。

  3. 串口操作编写代码,将频谱分析结果通过串口传输给电脑显示。

  4. 滤波

1) 设计好的滤波器抽头系数以数组方式存储在 EQs.h 文件中;

2) 编写代码,对 AD 采样信号进行滤波。

  1. 按键操作

编写代码,通过按键切换所使用的滤波器类型(低通、带通、高通、无滤波)。

  1. 载波生成、AM 调制

1) 修改fTransmit值改变载波频率:根据预设置的载波频率,通过分频算法得到近似的载波频率,并由串口输出;收音机频率需与载波频率相同;

2) AM 调制:将采样信号调制到波形上。

4. 相关知识及背景(限 150 字)

本实验是基于 Arduino板,利用采样、FFT和音频信号滤波知识,针对实际音频信号实现信号实时滤波处理的综合实验案例。需要学生了解信号调制解调及滤波的基本原理,能利用Arduino 分析信号频谱。通过本实验帮助学生结合工程实际由浅入深的理解数字信号分析及处理手段,使得学生真正能做到学有所用,提升对实际系统的综合分析和处理能力。

5. 实验环境条件

Arduino开发板一块、USB传输线一根、面包板一块、杜邦线若干、一个手机的耳机插头到Arduino的插头(把手机或者电脑的音频传到 Arduino板,用于 AD采样)、 $3 , 5 \mathrm { m m }$ 音频头。


图 1 Arduino 开发板

6. 教学目标与目的(限 150 字)

通过将采集的音频信号转化为数字信号,然后利用数字信号处理对信号进行频谱分析和滤波,最后再将信号转化为音频信号并调制输出,让学生理解数字信号实时处理的过程,认识基本的通信知识(调制与解调),并且熟悉Arduino 板以及Arduino 开发程序的过程。

7. 教学设计与实施进程

本实验利用 Arduino 实现了一个完整的音频信号处理流程。

1) 输入模拟信号,即待处理的音频信号;

2) 通过 Arduino 进行 $\mathrm { A } / \mathrm { D }$ 采样,将音频模拟信号转换为数字信号,便于后续处理;

3) 利用FFT 分析信号的频谱,串口传输给电脑显示;

4) 对信号进行滤波,去除噪声干扰;

5) 将滤波后的信号进行调制输出,解调后即为处理后的音频信号;

6) 学生通过实验理解信号处理以及通信的基本原理,熟悉 Arduino 编程语言;

7) 给学生一些提示,让其自主进行代码编写,提高学生的编程能力;

8) 实验结果评价:鼓励学生结合实验结果分析理论原理,并能结合思考题举一反三、深入理解实验所涉及有关数字信号处理的知识点,实现知识的内化;

9) 在实验完成后,组织学生以项目演讲、答辩、评讲的形式进行交流,了解不同的解决方案及特点,拓宽知识面。

8. 实验原理及方案

1)实验原理


图 2 实验架构

信号与采样:

信号是表示消息的物理量,如电信号可以通过幅度、频率、相位的变化来表示不同的消息。这种电信号有模拟信号和数字信号两类。模拟信号是指信号在时间和幅度上是连续的,可取无限多个值。数字信号是指不仅在时间上是离散的,而且在幅度上也是离散的,只能取有限个数值。

AD 采样通过抽样、量化和编码,将模拟信号转换为数字信号。抽样过程是将模拟信号在时间上离散化,用每隔一定时间的信号样本序列来代替原来在时间上连续的信号,使之成为抽样信号;量化是将抽样信号的幅度离散化使之成为数字信号;而编码则是将数字信号转换成数字系统所能接受的形式。

AD采样的步骤:首先将外部的信号,通过电路或者已有的AD芯片转换成引脚可以正确读取的电压信号。AD 位数越高,量化量级越小,转换后的数据幅值精度越高,采样的分辨率越好。通过增加量化位数,信噪比也随之提高。在Arduino中,利用定时器设置好采样率,然后将模拟量信号送到 $\mathrm { A } / \mathrm { D }$ 转换芯片。

在 Arduino 中,通常使用 analogRead()函数读取模拟输入引脚的值。模拟输入引脚读取电压的值的等级是从 0-5V,转换数值时值的范围是 0-1023,将这个读数值存储在名称为传感器值的变量中。根据需要,可以使用 map()函数将一个变量值等比例缩小并转换为另一个范围的值。采用 outputValue=map(sensorValue,0,1023,0,255),可以把 0-1023 的数值范围转换为 0-255的数值范围。


图 3 信号的采样

快速傅里叶变换(FFT):

根据 DFT 的特性,可以将一个长的 DFT 运算分解为若干短序列的 DFT 运算的组合,从而减少运算量,即FFT 算法。

按时间抽取的快速傅里叶变换(DIT-FFT)的方法,步骤为:

首先,将一个序列 $\mathtt { X }$ (n)一分为二,对于

$$ X ( k ) = \sum _ { n = 0 } ^ { N - 1 } x ( n ) W _ { N } ^ { n K } , k = 0 , 1 , . . . , N - 1 $$

设 $\mathrm { N }$ 是 2的整次幂 也就是 $\mathrm { N } { = } 2 \ \mathrm { \hat { M } }$ 。 $\mathrm { { x } \left( n \right) }$ 按照奇偶分组分别进行两组 DFT计算:

$$ \begin{array} { l } { { X ( k ) = \displaystyle \sum _ { r = 0 } ^ { ( N / 2 ) - 1 } x ( 2 r ) W _ { N } ^ { 2 r k } + \displaystyle \sum _ { r = 0 } ^ { ( N / 2 ) - 1 } x ( 2 r + 1 ) W _ { N } ^ { ( 2 r + 1 ) k } } } \ { { = \displaystyle \sum _ { r = 0 } ^ { ( N / 2 ) - 1 } x _ { 1 } ( r ) W _ { N } ^ { 2 r k } + W _ { N } ^ { k } \displaystyle \sum _ { r = 0 } ^ { ( N / 2 ) - 1 } x _ { 2 } ( r ) W _ { N } ^ { 2 r k } } } \end{array} \overset { ( \ast \ast - 1 ) } { \underset { ( \ast \ast ) = } { \overset { \ast \ast } { \mathcal { R } } } } { = } \mathrm { \frac { \Gamma _ { 1 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 1 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 2 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 2 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 1 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 2 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 2 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 2 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 2 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 2 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 2 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 2 } \ast } { \mathcal { R } \otimes \mathcal { L } } } { = } \mathrm { \frac { \Gamma _ { 2 } \ast } { \mathcal { R } \otimes \mathcal { L } } } $$

从而,一个N点的DFT就被分解为2个 $\mathrm { N } / 2$ 的 DFT,即DFT的前半部分。DFT的后半部分可以利用其对称性求出,后半部分为:

$$ X ( k + N / 2 ) = X _ { 1 } ( k ) - W _ { N } ^ { k } X _ { 2 } ( k ) , k = 0 , 1 , 2 , . . . , N / 2 - 1 $$

通过这样的分解,每一个 $\mathrm { N } / 2$ 点 DFT 只需 $( \mathrm { N } \hat { \mathrm { ~ 2 ) / 4 } }$ 次复数相乘计算,明显节省了运算量。

在 Arduino 中,可以通过 arduinoFFT.h 库中的函数实现 FFT 变换。对于 AD 采样信号,使用 FFT.Windowing 函数进行加窗处理,可以降低频谱泄露。使用 FFT.Compute 函数,可以计算出频谱,包含频率、幅度、相位。使用 FFT.ComplexToMagnitude 函数,可以取出不同频率下的幅度,即音频信号在该音符下的能量。

滤波:

设滤波系统传递函数 $\mathrm { H } \left( \mathrm { z } \right)$ ,原始音频信号通过滤波系统,输出 ${ \ Y } \left( \mathrm { { z } } \right) \mathrm { { = } } { \mathrm { { X } } \left( \mathrm { { z } } \right) } * { \mathrm { { H } } \left( \mathrm { { z } } \right) }$ 。考虑到频带及频带滤波增益,最终的信号输出为:

$$ Y ( \omega ) = \sum _ { i = 1 } ^ { B a n d C o u n t } a _ { i } ^ { * } X _ { i } ^ { } ( \omega ) ^ { * } H _ { i } ^ { } ( \omega ) $$

其中,BandCount 表示划分的子带个数;系数a表示对应频带的增益; $\mathrm { ~ H ~ } ( \mathrm { _ w } )$ 为对应频段的滤波器传递函数。

滤波系统 $\mathrm { H } \left( \mathrm { z } \right)$ 的常规表示为:

$$ H ( z ) = { \cfrac { Y ( z ) } { X ( z ) } } = { \cfrac { \displaystyle \sum _ { k = 0 } ^ { N } b _ { k } z ^ { - k } } { 1 - \displaystyle \sum _ { k = 1 } ^ { N } a _ { k } z ^ { - k } } } $$

转换到时域系统单位冲击响应表示为:

$$ y ( n ) = \sum _ { k = 1 } ^ { N } a _ { k } y ( n - k ) + \sum _ { k = 0 } ^ { N } b _ { k } x ( n - k ) $$

FIR 滤波器,通过对历史的采样值进行加权求和来实现信号滤波。

$$ y [ n ] = \sum _ { k = 0 } ^ { M } h [ k ] x [ n - k ] $$

$\mathrm { { x } [ \mathrm { { n - k } ] } }$ 为第 $\mathrm { k }$ 个采样值, $\mathrm { y } \mathrm { [ n ] }$ 为当前输出值,h[k]是滤波器对采样值 $\mathrm { { x } [ \mathrm { { n - k } ] } }$ 的权重,又叫

抽头系数, $\mathbb { M }$ 为滤波器阶数。在音频信号处理中,滤波也叫均衡。

EQs.h中给出了滤波器的抽头系数,在 Arduino中,利用时域卷积对采样后的信号进行滤波处理。

AM幅度调制:

使载波的振幅按照所需传送信号的变化规律而变化,但频率保持不变的。在通信系统中,若信号为 $m ( t )$ ,载波为 $c \left( t \right) = A \sin { \left( 2 \pi f _ { c } t \right) }$ ,则经过调制后信号变为

$$ s ( t ) = ( 1 + a \varGamma m ( t ) ) \varGamma c ( t ) $$

AM 调制后的信息,主要反映在调制后信号的包络幅度变化上,解调时可以采用包络检波器提取包络,或将接收信号与载波相乘再滤除高频部分。

PWM 波的产生:

PWM(Pulse Width Modulation)是一种方波控制信号。方波高电平的宽度在一个周期里的占比被称为占空比(Duty Cycle)。通过改变PWM的占空比,可以改变输出信号的平均电压,实现模拟电压的输出。Arduino Uno 里有三个 Timer:Timer0,Timer1,Timer2。三个 Timer 都可以自定义调整频率,但是各有特点。Timer0负责控制delay等函数,修改 Timer0的频率会导致计时函数不准;Timer1 的计数器是 16 位的,和 Timer0,Timer2 的 8 位计数器不一样;Timer2的频率可调的档位更多,因为它有 7 档预除数。代码中需要设置的引脚和寄存器包括三部分:pinMode,TCCR2A/B,OCR2A/B。

pinMode:

Timer2 所控制的管脚是 pin11 和 pin3(Timer0 控制 5,6;Timer1 控制 9,10),可以把这两个管脚设为输出。

OCR2A/B:

每个 Timer 里都有一个计数器和两个比较寄存器。Timer2 里计数器从 0 数到 255(8 位),然后归0继续从头数;Timer2的两个比较寄存器分别为 OCR2A和 OCR2B。

比较寄存器就是设置一个小于 255的数,比如 155。当计数器数到 0时输出为高电平,数到155的时候改变输出为低电平。这样就实现了占空比的调节。在普通模式下(Fast PWM),OCR2A控制 pin11 的占空比,OCR2B 控制 pin3 的占空比。

TCCR2A/B:

TCCR2A/B是用于控制Timer2计数器的模式与预除数的大小的。CS2位是用于控制 Timer2 计数器预除数的:_BV(CS22)|_BV(CS21)|_BV(CS20)的三部分由逻辑按位或“|”链接;每个 BV 是按位赋注(bit value)的意思; $_ { \mathrm { B V } } \left( \mathrm { C S 2 2 } \right) =$ 在 CS2 里, $1 \langle \zeta \mathcal { Q }$ (把 1 左移 2 位)=00000100;得到三部分分别是 00000100,00000010,00000001;按位或最终得到 0111;查代码里的表得到对应的预除数是1024。

Arduino 片内外设:

定时/计数器是Arduino工作的“节拍”,通过对来自内部或外部的脉冲信号进行计数的方式完成基本的定时/计数功能。在实际使用中,对输入时钟上升沿进行计数,输出溢出、比较信号。

定时/计数器


图 4 定时/计数器原理框图

在Arduino处理过程中,需要加入中断操作。在Arduino中,可以使用电平的变化来触发中断,attachInterrupt(intr_id, ISR, mode)函数可以用来控制按键中断。其中 intr_id 是中断号,和引脚号的对应关系通过 digitalPinToInterrupt 函数查询,ISR 是中断服务函数名,任意void ()类型的函数即可,mode 是触发中断的模式,可以选择 LOW、CHANGE、RISING、FALLING。

实验电路图:


图 5 实验电路连接图

2)实现方案


图 6 实验流程图

首先,电脑或手机输出音频模拟信号,然后送入 Arduino进行 AD 采样。AD 采样后的信号通过FFT变换进行频谱分析,并通过串口传输给电脑显示。为了降低频谱泄露的值,可以先对信号进行加窗操作,然后进行频谱分析,计算频谱及其频率值、幅度以及相位。

其次,对 AD采样后的信号进行滤波消除噪声干扰。滤波可以选择不同的滤波器,滤波器的选择为芯片的中断控制,需要注意的是设置好的滤波器抽头系数需提前保存在文件中。

然后,本地频率发生器进行AM载波信号的形成。根据预设置载波频率,通过分频算法得到最终的载波频率,并在串口输出。将AM 调制的信号与采样滤波后的信号进行混频输出,并通过裸的杜邦线无线发射出去。

最后,利用收音机作为接收端,接收并播放Arduino发射的音频信号。需要注意的是收音机频率要和载波频率基本一致,否则接收不到信号。

9. 实验报告要求

实验报告需要反映以下工作:

1) 实验需求分析:明确实验目的、实验内容、实验任务以及最终需要达到的实验效果;

2) 实验原理分析:结合实验的数学原理,分析信号采样、滤波以及调制对实验结果的影响;

3) 理论推导计算:结合 Arduino 电路和数字信号处理的基本原理,分析计算实验应选用的相关参数,思考硬件编程的逻辑;

4) 实验过程及结果记录:利用不同的方法及参数进行实验,记录相应的现象及处理结果;

5) 数据处理分析:根据数据、算法参数进行计算、分析与评价,说明实验结果是否符合实验原理给出的理论参考;

6) 实验结果总结:结合数字信号处理的相关理论,总结实验,在同学之间进行充分的交流讨论,进一步加深对理论的理解,锻炼独立思考的能力,并回答课后思考题。

10.考核要求与方法(限 300 字)


图 7 实验电路实物图

1) 实验结果检查:实验操作规范,实验结果准确合理。现场修改实验参数,运行 Arduino程序,进行结果展示,并能阐述结果产生的原因;

2) 现场提问:对照学生的实验结果,对实验现象、实验原理等环节进行提问,学生须现场验证或回答,要求能从实验原理出发论证实验现象,或能从实验现象出发探寻其中的实验原理;

3) 实验数据:实验整理的数据是否完整、全面,实验编写的代码是否规范、有效;

4) 实验报告:实验报告是否具有规范性与完整性,实验原理的理解是否透彻,是否能根据实验现象独立思考做出总结,是否能正确回答实验思考题。

11.项目特色或创新(可空缺,限 150 字)

本项目作为基于 Arduino开发板的数字信号处理实验,设计思路较为新颖。本实验既能让学生巩固和掌握Arduino 开发板的使用和编程,又能巩固学生对AD采样、滤波器设计、离散傅里叶变换、调制解调的理解,理论结合实际,将抽象的理论形象化、具体化,激发学生学习兴趣。同时在整个实验过程中培养学生的自主学习、独立思考与综合分析能力。

获奖信息

获奖等级 一等奖
年份 2022

作品信息

学时分类 1-6学时
课程分类 课内:数字信号处理、

作者信息

作者
魏少明,陈鹏辉,张玉玺
学校
北京航空航天大学
院系
电子信息工程学院

电工电子实验教学资源平台 苏ICP备09069895号-19