电子科技大学数字信号处理DSP课程设计钢琴音符识别.docx

上传人:b****5 文档编号:11954625 上传时间:2023-04-16 格式:DOCX 页数:14 大小:20.34KB
下载 相关 举报
电子科技大学数字信号处理DSP课程设计钢琴音符识别.docx_第1页
第1页 / 共14页
电子科技大学数字信号处理DSP课程设计钢琴音符识别.docx_第2页
第2页 / 共14页
电子科技大学数字信号处理DSP课程设计钢琴音符识别.docx_第3页
第3页 / 共14页
电子科技大学数字信号处理DSP课程设计钢琴音符识别.docx_第4页
第4页 / 共14页
电子科技大学数字信号处理DSP课程设计钢琴音符识别.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

电子科技大学数字信号处理DSP课程设计钢琴音符识别.docx

《电子科技大学数字信号处理DSP课程设计钢琴音符识别.docx》由会员分享,可在线阅读,更多相关《电子科技大学数字信号处理DSP课程设计钢琴音符识别.docx(14页珍藏版)》请在冰豆网上搜索。

电子科技大学数字信号处理DSP课程设计钢琴音符识别.docx

电子科技大学数字信号处理DSP课程设计钢琴音符识别

资料范本

 

本资料为word版本,可以直接编辑和打印,感谢您的下载

 

电子科技大学数字信号处理DSP课程设计-钢琴音符识别

 

地点:

__________________

时间:

__________________

 

说明:

本资料适用于约定双方经过谈判,协商而共同承认,共同遵守的责任与义务,仅供参考,文档可直接下载或修改,不需要的部分可直接删除,使用时请详细阅读内容

2014级数字信号处理课程设计报告

题目:

钢琴音符识别

姓名:

邱晨曦

学号:

2014010909008

答辩时间:

2016/12/9

一.题目要求:

(1)播放和记录一段钢琴音乐中的音符;

(2)记录到音符以后,找到音符所对应的现代标准钢琴的钢琴键,并分析结果。

二.课程设计思路:

涉及到的知识点:

快速傅里叶变换、钢琴音频信号的时域和频域的特性、能熵比的概念、频率校正、频率与音符的转换关系。

方案分析:

预处理部分:

直接用audioread函数读出来的原始数据。

优点:

准确率较高;

缺点:

数据量较大,采样频率为44kHz,远大于奈奎斯特采样率。

以11kHz的采样率重新采样,并转换为单声道。

优点:

数据量小了很多,易于处理;

缺点:

牺牲了部分的准确率,但对于音符的判断影响可以忽略。

B.端点检测算法:

<1>.双门限法:

1.计算短时能量(高门限)和过零率(低门限);

2.选取一个较高的门限,语音信号的能量包络大部分都在此门限之上,进行一次初判,语音起止点位于该门限与短时能量包络交点所对应的时间间隔之外;

3.根据噪声能量,确定一个较低的门限,并从初判起点往左,从初判终点往右搜索,分别找到能零比曲线第一次与门限相交的两个点,两点之间段就是用双门限方法所判定的语音段;

4.以短时平均过零率为准,从低门限点往左右搜索,找到短时平均过零率低于某阈值的两点,为语音的起止点;

图1:

双门限法示意图

说明:

算法中的阀值是根据实验过程调节的。

该算法在实际应用的过程中发现:

在语音信号频率分布较为集中的时候,端点检测出来的结果比较准确,但当语音信号频率分布比较分散的时候,很难通过控制固定的阀值来检测到每个音符;

<2>.自相关法:

由于两种信号的自相关函数存在极大的差异,可以利用这种差别来提取语音端点。

根据噪声的情况,设置两个阈值和,当相关函数最大值大于时,便判定是语音;当相关函数最大值大于或小于时,则判定为语音信号的端点。

该算法同样存在当语音信号频率分布较广的时候,阀值比较难控制的问题。

<3>.基于谱熵的端点检测:

基于谱熵语音端点检测方法是通过检测谱的平坦程度,来进行语音端点检测的,为了更好进行语音端点检测,采用语音信号的短时功率谱构造语音信息谱熵,从而对语音段和噪声段进行区分。

检测思路:

对语音信号进行分帧加窗;

计算每一帧的谱能量;

计算出每一帧中每个样本点的概率密度函数;

计算出每一帧的谱熵值(由信息论知识知道,熵值在自变量服从均匀分布的时候,熵值达到最大值,所以噪声的熵值是比较大的,而钢琴音符的熵值是比较小的,由此区别了噪声和音符);

设置判决门限;

根据各帧的谱熵值进行端点检测。

在实验过程中发现:

依然存在当语音信号频率分布较广时,阀值不太好控制的问题。

因此对该方法进行改进,引入,能熵比的概念:

谱熵值类似于过零率,能熵比的表示为。

由于噪声和信号的能熵比差别很大。

因此在能熵比的图像中,每一个“尖刺”就代表了一个特定频率的语言信号。

图2:

能熵比图中的“尖刺”

在检测过程中,依然不能通过简单的设置阀值的办法来进行端点检测,原因是语音频率分布较广时,每个音符的能熵比变化范围差别较大,如下图所示,有的“尖刺”完全在门限之上,而有的则完全在门限之下。

图3:

88阶全音的能熵比图

因此,采用检测能熵比中的“低谷点”(该点比左右两边的一定数目的点的能熵比都小)的方法。

语音信号一定位于两个低谷点之间的部分,再对低谷点进行适当的左右移动作为语音信号的起止点。

如下图所示:

图4:

标记起止点的能熵比图

(绿色为起始点,红色为截止点)

设计框架和流程:

用audioread函数读入钢琴音乐,并用sound函数播放;

2.为了方便处理,对信号以11.025kHz的频率进行重新采样,并统一转换成单声道的信号;

3.因为语言信号可以在短时间内认为是平稳的,因此对语音信号进行分帧的处理,设置帧长320,为了减小误差,两帧之间设置重叠部分,因此帧移取80;

4.计算每一帧的能熵比;

5.找到能熵比中的“低谷点”(该点比左右两边的一定数目的点的能熵比都小);

6.如果两个低谷点之间的距离大于miniL(认为持续长度超过一定长度的为音符,最小长度miniL可自行设置)。

则低谷点右移sr(即shiftright,数值可自行调节)帧作为一段信号的起始点,将低谷点左移sl(即shiftleft,数值可自行调节)帧作为截止点[注:

采用该方法的优点是通过调节相关参数能适应多种情况,缺点是检测环境发生较大变化时,需要重新设置参数];

7.将找到的语音段转换成未分帧时对应坐标的语音段,并对每段做快速傅里叶变换;

8.找到每段快速傅里叶变换中的最大值以及最大值所对应的横坐标(fft点),将横坐标转换成相应的频率,得到的频率即为该段音符的频率;

9.利用比值法进行频率的校正,窗函数选择矩形窗;

10.根据检测到的频率确定音符,计算公式为:

,为第几个按键,再通过查表得到对应音符;

11.分析结果。

三.具体设计过程:

部分代码(测试部分缺省):

主函数部分:

[x,fs]=audioread('钢琴音频.WAV');

formatshort;

wlen=320;inc=80;%分帧的帧长和帧移

overlap=wlen-inc;%帧之间的重叠部分

sound(x,fs);%播放音乐

x=calsample(x,fs);%为了方便处理,重新以11025Hz的频率采样,并转换成单声道

x=x-mean(x);%消去直流分量

x=x/max(abs(x));%幅值归一化

y=Enframe(wlen,inc,x)';%分帧

fn=size(y,2);%取得帧数

time=(0:

length(x)-1)/11025;%计算时间坐标

frameTime=frame2time(fn,wlen,inc,11025);%计算各帧对应的时间坐标

sr=2;sl=13;miniL=33;%配置左右移动的帧数和要求的最短帧数

[voicesegment,vos,Ef]=get_segment(y,fn,sr,sl,miniL);%获得语音段

[real_f,ft,ax]=get_f(x,voicesegment,vos,wlen,inc);%检测频率的结果

fori=1:

length(real_f)

real_f(i)=roundn(real_f(i),-4);

end

fori=1:

length(real_f)

real_node(i)=get_node(real_f(i))

end

%**********************************绘图部分********************************

subplot211;

stem(real_f);

title('频率检测结果');xlabel('音符/个');ylabel('频率/Hz');

subplot212;

stem(real_node,'r');

title('音符检测结果');xlabel('音符/个');ylabel('对应按键');

figure

(2);

subplot211;

plot(Ef);

title('能熵比图及语音起止点');xlabel('帧数/个');ylabel('能熵比');

fori=1:

length(voicesegment)

text(voicesegment(i).begin,Ef(voicesegment(i).begin),'o','color','g')

text(voicesegment(i).end,Ef(voicesegment(i).end),'o','color','r')

end

subplot212,plot(time,x,'k');title('语音信号端点检测结果')

axis([0max(time)-11]);ylabel('幅值');

fork=1:

vos%标出有话段

nx1=voicesegment(k).begin;

nx2=voicesegment(k).end;

nxl=voicesegment(k).duration;

fprintf('%4d%4d%4d%4d\n',k,nx1,nx2,nxl);

subplot212

line([frameTime(nx1)frameTime(nx1)],[-11],'color','r','linestyle','-');

line([frameTime(nx2)frameTime(nx2)],[-11],'color','r','linestyle','--');

end

其中的用到的子函数:

1.calsample.m(调整采样率和声道)

functionsample=calsample(sampledata,FS)

temp_sample=resample(sampledata,1,FS/11025);%调整采样频率

[~,n]=size(temp_sample);

if(n==2)%转换成单声道

sample=temp_sample(:

1);

else

sample=temp_sample;

end

end

2.Enframe.m(分帧函数)

functionf=Enframe(len,inc,x)%对读入的语音进行分帧,len为帧长,

%inc为帧重叠样点数,x为输入语音数据

fh=fix(((size(x,1)-len)/inc)+1);%计算帧数

f=zeros(fh,len);%设置一个零矩阵,行为帧数,列为帧长

i=1;

n=1;

whilei<=fh%帧间循环

j=1;

whilej<=len%帧内循环

f(i,j)=x(n);

j=j+1;

n=n+1;

end

n=n-len+inc;%下一帧开始位置

i=i+1;

end

3.frame2time.m(坐标刻度转换)

functionframeTime=frame2time(frameNum,framelen,inc,fs)

frameTime=(((1:

frameNum)-1)*inc+framelen/2)/fs;%求对应的时间坐标

4.get_segment.m(端点检测,确定音符段)

function[voicesegment,vos,Ef]=get_segment(y,fn,sr,sl,miniL)

ifsize(y,2)~=fn,y=y';end%把y转换为每列数据表示一帧语音信号

wlen=size(y,1);%取得帧长

fori=1:

fn

Sp=abs(fft(y(:

i)));%FFT取幅值

Sp=Sp(1:

wlen/2+1);%只取正频率部分

Esum(i)=sum(Sp.*Sp);%计算能量值

prob=Sp/(sum(Sp));%计算概率

H(i)=-sum(prob.*log(prob+eps));%求谱熵值

end

hindex=find(H<0.1);

H(hindex)=max(H);

Ef=sqrt(1+abs(Esum./H));%计算能熵比

Ef=Ef/max(Ef);%归一化

[x1,y1]=get_max(Ef);%找到能熵比中的“高峰点”

[x2,y2]=get_min(Ef);%找到能熵比中的“低估点”

voicesegment

(1).begin=x1

(1)-8;%由于仅仅靠低谷点无法检测出第一个音符起始位置,因此将高峰点的第一个值左移8帧作为第一个音符的起始点

voicesegment

(1).end=x2

(1)-sl;%将第一个低谷点作为第一个音符的截止点

voicesegment

(1).duration=voicesegment

(1).end-voicesegment

(1).begin+1;%一个音符的持续帧数

j=1;

fork=2:

length(x2)%将找到的低谷点作为音符的起止点

ifx2(k)-x2(k-1)>=miniL%剔除持续帧长度小于miniL的音符段

j=j+1;

temp1=x2(k-1)+sr;%将低谷点右移sr个帧,作为一个音符的起始点

voicesegment(j).begin=temp1;

temp2=x2(k)-sl;%将低谷点左移sl个帧,作为一个音符的截止点

voicesegment(j).end=temp2;

voicesegment(j).duration=voicesegment(j).end-voicesegment(j).begin+1;%音符持续帧数

end

end

vos=length(voicesegment);%返回音符个数

end

5.get_max.m(找到高峰点)

function[max_x,max]=get_max(x)

l=length(x);%获得数组的长度

max=[];

max_x=[];

j=1;

fori=20:

l-15%找到“峰值点”

if(x(i)>x(i-1))&&(x(i)>x(i-2))&&(x(i)>x(i-3))&&(x(i)>x(i-4))&&(x(i)>x(i-5))...

&&(x(i)>x(i-6))&&(x(i)>x(i-7))&&(x(i)>x(i-8))&&(x(i)>x(i-9))&&(x(i)>x(i-10))...

&&(x(i)>x(i-11))&&(x(i)>x(i-12))&&(x(i)>x(i-13))&&(x(i)>x(i-14))...

&&(x(i)>x(i-15))&&(x(i)>x(i-16))&&(x(i)>x(i-17))...

&&(x(i)>x(i+1))&&(x(i)>x(i+2))&&(x(i)>x(i+3))&&(x(i)>x(i+4))&&(x(i)>x(i+5))...

&&(x(i)>x(i+6))&&(x(i)>x(i+7))&&(x(i)>x(i+8))&&(x(i)>x(i+9))&&(x(i)>x(i+10))...

&&(x(i)>x(i+11))&&(x(i)>x(i+11))&&(x(i)>x(i+12))&&(x(i)>x(i+13))&&(x(i)>x(i+14))...

&&(x(i)>x(i+15))&&(x(i)>x(i+16))...

&&(x(i)>0.1)

max_x(j)=i;%找到后赋值给返回参数

max(j)=x(i);

i=i+1;

j=j+1;

else

i=i+1;

end

end

end

6.get_min.m(找到低谷点)

function[min_x,min]=get_min(x)

l=length(x);%获得数组的长度

min=[];

min_x=[];

j=1;

fori=100:

l-10%寻找低谷点

if(x(i)

&&(x(i)

&&(x(i)

&&(x(i)

&&(x(i)

&&(x(i)

&&(x(i)

&&(x(i)

&&(x(i)

min_x(j)=i;%找到后赋值给返回值

min(j)=x(i);

i=i+1;

j=j+1;

else

i=i+1;

end

end

end

7.get_f.m(确定频率)

function[real_f,ft,ax]=get_f(x,voicesegment,vos,wlen,inc)

fori=1:

vos%横坐标转化,将起止点坐标的单位由帧转换成点

ax(i).begin=(voicesegment(i).begin-1)*inc+1;

ax(i).end=(voicesegment(i).end-1)*inc+wlen;

ax(i).duration=ax(i).end-ax(i).begin+1;

temp=x(ax(i).begin:

ax(i).end);%获得语音段

ft{i}=fft(temp);%做快速傅里叶变换,并将结果保存在元胞矩阵中

ft{i}=abs(ft{i});%将得到的fft去模值

[fm(i),fm_x(i)]=max(ft{i});%找到每个语音段对应的fft中的最大值及最大值对应的横坐标

real_f1(i)=fm_x(i)*11025./ax(i).duration;%进行频率转换,将横坐标乘以分辨率得到真实频率

real_f(i)=Specorrm(x(ax(i).begin:

ax(i).end),11025,ax(i).duration,real_f1(i)-10,real_f1(i)+10);

%利用比值法进行频率修正,窗函数选择矩形窗

end

8.Specorrm.m(频率校正)

functionZ=Specorrm(x,fs,N,nx1,nx2)

%x是被测信号,fs是采样频率N为FFT的长度,nx1和nx2被测信号频率的区间,nx2>nx1

[nx,mx]=size(x);

ifmx==1,x=x';end%转换成行矩阵

[nx,mx]=size(x);

M=fix(N/2)+mod(N,2);

xf=fft(x);

%xf=xf(1:

M)*2/N;

ddf=fs/N;%频率分辨率

n1=fix(nx1/ddf);%将频率转换成fft对应的点

n2=round(nx2/ddf);

A=abs(xf);%取fft的模值

[Amax,index]=max(A(n1:

n2));%找到fft点n1到n2之间幅值的最大值

index=index+n1-1;%移动到n1和n2中间

%比值法

%加矩形窗

indsecL=A(index-1)>A(index+1);%满足条件则为1,不满足则为0

df=indsecL.*A(index-1)./(Amax+A(index-1))-(1-indsecL).*A(index+1)./(Amax+A(index+1));

Z=(index-1-df)*ddf;%修正后的频率

end

9.get_node.m(确定音符)

functionnode=get_node(f)

node=12*log2(f/440)+49;

node=round(node);%四舍五入确定对应按键

end

生成的图与数据等LINKExcel.Sheet.12"C:

\\Users\\pc\\Desktop\\端点检测结果.xlsx""Sheet1!

R2C1:

R38C4"\a\f5\h\*MERGEFORMAT

对数据的分析:

红色标记出检测错误的音符。

上表为检测结果的统计及误差统计。

大部分误差都小于1%,平均误差为0.82%,误差较小.音符检测发生一个错误,正确了为97.14%,很好地完成了任务。

四.总结:

收获

小组分工情况

小组就邱晨曦一个人,邱晨曦负责全部工作。

LINKExcel.Sheet.12"工作簿1""Sheet1!

R1C1:

R36C8"\a\f5\h\*MERGEFORMAT

参考文献:

谢明,丁康:

离散频谱的一种新校正方法,重庆,载重庆大学学报:

1995年3月第8卷第2期47~54

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 演讲主持

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1