基音周期识别求解释

下载作业帮安装包
扫二维码下载作业帮
1.75亿学生的选择
基音和范音是什么意思啊?最好通俗一点的说法,谢了
冥心宝贝h0D
基音它的定义是:物体振动时所发出的频率最低的音,其余为泛音.也就是发音体整段振动.基音决定了音高.泛音 它的定义是:除了发音体整体振动产生的基音外,其1/2、1/3、1/4等各部分也是同时振动,比如:当奏大提琴的最低音C音时,弦的振动里就包含了图示的那种振动.泛音的组合决定了特定的音色,并能使人明确地感到基音的响度.乐器和自然界里所有的音都有泛音举例来说明:我们弹吉他的时候,按住某品然后拨响相应的弦,此时发出的音就是基音.我们把手指轻放在6弦七品品柱上然后拨响弦,瞬间把手指松开,这时候听到一个比原本应该发出的音高了好多的音,这就是泛音(自然泛音).而音色包括了基音和泛音,音色的好坏主要是由泛音的多寡及泛音之间的相对强度来决定.而单独的说泛音怎么样没有什么意义,泛音离不开基音.我们来判断一个音的音高是判断基音的音高而不是泛音.只有基音和泛音同时进入共鸣区共鸣才能够表现出很好的音色.而泛音是每个人都会有的,我们来判断每个人的声音就是靠的彼此之间泛音的不同来判断,所以泛音的好坏决定着音色的好坏.
为您推荐:
其他类似问题
扫描下载二维码基音检测算法研究及其在方言辨识中的应用_图文_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
基音检测算法研究及其在方言辨识中的应用
上传于||文档简介
&&基音检测
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩63页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢您的位置: &
一种汉语单音节基音提取与声调识别方法
优质期刊推荐21264人阅读
OpenCV(28)
语音识别与TTS(12)
图像处理(54)
语音信号处理之(二)基音周期估计(Pitch Detection)&&&&&&& 这学期有《语音信号处理》这门课,快考试了,所以也要了解了解相关的知识点。呵呵,平时没怎么听课,现在只能抱佛脚了。顺便也总结总结,好让自己的知识架构清晰点,也和大家分享下。下面总结的是第二个知识点:基音周期估计。我们用C++实现了基于自相关函数法的基音周期检测,并且结合了OpenCV来显示语音波形。因为花的时间不多,所以可能会有不少说的不妥的地方,还望大家指正。谢谢。&一、概述1.1、基音与基音周期估计&&&&&& 人在发音时,根据声带是否震动可以将语音信号分为清音跟浊音两种。浊音又称有声语言,携带者语言中大部分的能量,浊音在时域上呈现出明显的周期性;而清音类似于白噪声,没有明显的周期性。发浊音时,气流通过声门使声带产生张弛震荡式振动,产生准周期的激励脉冲串。这种声带振动的频率称为基音频率,相应的周期就成为基音周期。&&&&&& 通常,基音频率与个人声带的长短、薄厚、韧性、劲度和发音习惯等有关系,在很大程度上反应了个人的特征。此外,基音频率还跟随着人的性别、年龄不同而有所不同。一般来说,男性说话者的基音频率较低,而女性说话者和小孩的基音频率相对较高。 基音周期的估计称谓基音检测,基音检测的最终目的是为了找出和声带振动频率完全一致或尽可能相吻合的轨迹曲线。&&&&&& 基因周期作为语音信号处理中描述激励源的重要参数之一,在语音合成、语音压缩编码、语音识别和说话人确认等领域都有着广泛而重要的问题,尤其对汉语更是如此。汉语是一种有调语言,而基因周期的变化称为声调,声调对于汉语语音的理解极为重要。因为在汉语的相互交谈中,不但要凭借不同的元音、辅音来辨别这些字词的意义,还需要从不同的声调来区别它,也就是说声调具有辨义作用;另外,汉语中存在着多音字现象,同一个字的不同的语气或不同的词义下具有不同的声调。因此准确可靠地进行基音检测对汉语语音信号的处理显得尤为重要。&1.2、基音周期估计的现有方法&&&&& 到目前为止,基音检测的方法大致上可以分为三类:1)时域估计法,直接由语音波形来估计基音周期,常见的有:自相关法、并行处理法、平均幅度差法、数据减少法等;2)变换法,它是一种将语音信号变换到频域或者时域来估计基音周期的方法,首先利用同态分析方法将声道的影响消除,得到属于激励部分的信息,然后求取基音周期,最常用的就是倒谱法,这种方法的缺点就是算法比较复杂,但是基音估计的效果却很好;3)混合法,先提取信号声道模型参数,然后利用它对信号进行滤波,得到音源序列,最后再利用自相关法或者平均幅度差法求得基因音周期。&三、基于自相关的基音周期检测3.1、自相关函数&&&&& 能量有限的语音信号x(n)的短时自相关函数定义为:&&&& &&&&&& 此公式表示一个信号和延迟m点后该信号本身的相似性。如果信号x(n)具有周期性,那么它的自相关函数也具有周期性,而且周期与信号x(n)的周期性相同。自相关函数提供了一种获取周期信号周期的方法。在周期信号周期的整数倍上,它的自相关函数可以达到最大值,因此可以不考虑起始时间,而从自相关函数的第一个最大值的位置估计出信号的基音周期,这使自相关函数成为信号基音周期估计的一种工具。&3.2、短时自相关函数法&&&&&&& 语音信号是非稳态信号它的特征是随时间变化的,但在一个很短的时间段内可以认为具有相对稳定的特征即短时平稳性。因此语音具有短时自相关性。这个时间段约5ms-50ms。为其统计特性和频谱特性都是对短时段而言的。这使得要对语音信号作数字处理必须先按短时段对语音信号分帧。这样每一帧信号都具有短时平稳性从而进行短时相关分析。&&&&& 能量有限的语音信号s(n)的短时自相关函数定义为:&&&&&& 一般要求一帧至少包含2个以上的周期。一般,基频最低50Hz,故周期最长为20ms。而且相邻帧之间要有足够的重叠。具体应用时,窗口长度根据采样率确定帧长。&&&&&& 该帧的自相关函数中,除去第一个最大值后(0处),最大值Kmax= 114,那么该帧对应的基频16kHz/114=140Hz。&四、基于自相关的基音周期检测算法实现&&&&&& 这个实现课程要求是用C++来实现的。然后为了画波形,我用到了我比较熟悉的OpenCV。OpenCV画出来的波形还是不错的,而且如果是动态的波形平移,挺好看的,就像心电图那么动人。&&&&& 实验采用一段男声读“播放”两个字的声音wav文件,其为16KHz采样率,16bit量化。整段语音长656.7ms,节点共10508个。&& &&&&& 我们先要确定帧长。下面分别是帧长200,320和400个节点时所包含的周期数。200时只有一个周期,而400有三个周期,所以我们采用400的帧长。&&&& 通过计算短时能量区分voice和unvoice。语音信号{x(n)}的某帧信号的短时平均能量En的定义为:&&&&&& 语音中浊音段的短时平均能量远远大于清音段的短时平均能量。因此,短时平均能量的计算给出了区分清音段与浊音段的依据,即En(浊)&En(清)。&&&&& 计算每一帧的过程中,会显示在原来波形中的位置,并且实时显示该帧得到的基音周期。另外还会在另一个窗口实时显示该帧的原始波形。&&&&& 该帧的原始波形图(以下为不同时间的两帧,会动态变化):&&&&&& 下面左边的图是计算该语音的所有帧对应的基音周期的点,由图可以看出存在不少的野点。因为,需要对此进行进一步的处理,即去除野点。这里通过中值滤波来除去野点,滤波结果见右图。C++程序如下:(每按一次空格进入下一个步骤)// Description : Pitch detection
: Zou Xiaoyi
// HomePage
: http://blog.csdn.net/zouxy09
#include &iostream&
#include &fstream&
#include &opencv2/opencv.hpp&
#include &ReadWriteWav.h&
#include &string&
#define MAXLENGTH 1000
void wav2image(Mat &img, vector&short& wavData, int wav_start, int width, int max_amplitude)
short max(0), min(0);
for (int i = 0; i & wavData.size(); i++)
if (wavData[i] & max)
max = wavData[i];
if (wavData[i] & min)
min = wavData[i];
cout&&max&&'\t'&&min&&
max_amplitude = max_amplitude & 480 ? 480 : max_
// normalize
for (int i = 0; i & wavData.size(); i++)
wavData[i] = (wavData[i] - min) * max_amplitude / (max - min);
int j = 0;
Point prePoint, curP
if (width &= 400)
img.create(max_amplitude, width, CV_8UC3);
img.setTo(Scalar(0, 0, 0));
for (int i = wav_ i & wav_start + i++)
prePoint = Point(j, img.rows - (int)wavData[i]);
line(img, prePoint, curPoint, Scalar(0, 255, 0), 2);
curPoint = preP
if (width & MAXLENGTH)
cout&&&The wav is too long to show, and it will be resized to 1200&&&
resize(img, img, Size(MAXLENGTH, img.rows));
img.create(max_amplitude, 400, CV_8UC3);
img.setTo(Scalar(0, 0, 0));
for (int i = wav_ i & wav_start + i++)
prePoint = Point(j*400/width, img.rows - (int)wavData[i]);
circle(img, prePoint, 3, Scalar(0, 0, 255), CV_FILLED);
cout&&&The wav is too small to show, and it will be resized to 400&&&
short calOneFrameACF(vector&short& wavFrame, int sampleRate)
vector&float&
acf.empty();
// calculate ACF
for (int k = 0; k & wavFrame.size(); k++)
float sum = 0.0;
for (int i = 0; i & wavFrame.size() - i++)
sum = sum + wavFrame[i] * wavFrame[ i + k ];
acf.push_back(sum);
// find the max one
float max(-999);
int index = 0;
for (int k = 0; k & wavFrame.size(); k++)
if (k & 25 && acf[k] & max)
max = acf[k];
return (short)sampleRate /
int main()
const char *wavFile = &bofang.wav&;
vector&short&
int nodesPerFrame = 400;
/************* Write data to file part Start ***************/
fstream writeF
writeFile.open(&statistics.txt&, ios::out);
/************* Write data to file part End ***************/
/************* Read and show the input wave part Start ***************/
int sampleR
int dataLength = wav2allsample(wavFile, data, sampleRate);
if (!dataLength)
cout &&&Reading wav file error!&&&
return -1;
Mat originalW
wav2image(originalWave, data, 0, dataLength, 400);
line(originalWave, Point(0, originalWave.rows * 0.5), Point(originalWave.cols, originalWave.rows * 0.5), Scalar(0, 0, 255), 2);
imshow(&originalWave&, originalWave);
// write data
writeFile&&&Filename: &&&wavFile&&endl&&&SampleRate: &&&sampleRate&&&Hz&&&endl&&&dataLength: &&&dataLength&&
cout&&&Press space key to continue&&&
while (waitKey(30) != ' ');
/************* Read and show the input wave part End ***************/
/******** Calculate energy to separate voice and unvoice part Start *********/
int nodeCount = 0;
// The sum must be double type
vector&double& energyT
double maxEnergy(0);
while(nodeCount & (dataLength - nodesPerFrame))
double sum(0);
for (int i = nodeC i & (nodeCount + nodesPerFrame); i++)
sum += (double)data[i] * data[i];
if (sum & maxEnergy)
maxEnergy =
energyTmp.push_back(sum);
nodeCount++;
// Transform to short type for show
vector&short&
// Fill element of boundary
short tmp = (short)(energyTmp[0] * 400 / maxEnergy);
for (int i = 0; i & nodesPerFrame * 0.5; i++)
energy.push_back(tmp);
for (int i = 0; i & energyTmp.size(); i++)
energy.push_back((short)(energyTmp[i] * 400 / maxEnergy));
// Fill element of boundary
tmp = (short)(energyTmp[energyTmp.size() - 1] * 400 / maxEnergy);
for (int i = 0; i & nodesPerFrame * 0.5; i++)
energy.push_back(tmp);
wav2image(showEnergy, energy, 0, energy.size(), 400);
line(showEnergy, Point(0, showEnergy.rows - 1), Point(showEnergy.cols, showEnergy.rows - 1), Scalar(0, 0, 255), 2);
imshow(&showEnergy&, showEnergy);
while (waitKey(30) != ' ');
// separate voice and unvoice
float thresVoice = 400 * 0.15;
line(showEnergy, Point(0, showEnergy.rows - thresVoice), Point(showEnergy.cols, showEnergy.rows - thresVoice), Scalar(0, 255, 255), 2);
imshow(&showEnergy&, showEnergy);
while (waitKey(30) != ' ');
// Find the Transition point and draw them
bool high =
vector&int& separateN
for (int i = 0; i & energy.size(); i++)
if ( !high && energy[i] & thresVoice)
separateNode.push_back(i);
writeFile&&&UnVoice to Voice: &&&i&&
line(showEnergy, Point(i * MAXLENGTH / dataLength, 0), Point(i * MAXLENGTH / dataLength, showEnergy.rows), Scalar(255, 255, 255), 2);
putText(showEnergy, &Voice&, Point(i * MAXLENGTH / dataLength, showEnergy.rows * 0.5 + 40), FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 255, 255), 2);
imshow(&showEnergy&, showEnergy);
while (waitKey(30) != ' ');
if ( high && energy[i] & thresVoice)
separateNode.push_back(i);
writeFile&&&Voice to UnVoice: &&&i&&
line(showEnergy, Point(i * MAXLENGTH / dataLength, 0), Point(i * MAXLENGTH / dataLength, showEnergy.rows), Scalar(255, 0, 0), 2);
putText(showEnergy, &UnVoice&, Point(i * MAXLENGTH / dataLength, showEnergy.rows * 0.5 + 40), FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 0, 0), 2);
imshow(&showEnergy&, showEnergy);
while (waitKey(30) != ' ');
/******** Calculate energy to separate voice and unvoice part End ***********/
/******************* Calculate all frame part Start ***************/
int frames = 0;
vector&short& allPitchF
writeFile&&&The pitch frequency is:&&&
while(frames & 2 * dataLength / nodesPerFrame)
vector&short& wavF
wavFrame.empty();
// get one frame, 400 nodes per frame, and shift 200 nodes, or overlap 200 nodes
int start = frames * nodesPerFrame * 0.5;
for (int i = i & start + nodesPerF i++)
wavFrame.push_back(data[i]);
// calculate the ACF of this frame
float pitchFreqency = calOneFrameACF(wavFrame, sampleRate);
allPitchFre.push_back(pitchFreqency);
cout&&&The pitch frequency is: &&&pitchFreqency &&& Hz&&&
writeFile&&pitchFreqency&&
// show current frame in the whole wave
Mat originalW
wav2image(originalWave, data, 0, dataLength, 400);
line(originalWave, Point(0, originalWave.rows * 0.5), Point(originalWave.cols, originalWave.rows * 0.5), Scalar(0, 0, 255), 2);
line(originalWave, Point(start * MAXLENGTH / dataLength, 0), Point(start * MAXLENGTH / dataLength, originalWave.rows), Scalar(0, 0, 255), 2);
line(originalWave, Point((start + nodesPerFrame)* MAXLENGTH / dataLength, 0), Point((start + nodesPerFrame)* MAXLENGTH / dataLength, originalWave.rows), Scalar(0, 0, 255), 2);
// put the pitchFreqency of this frame in the whole wave
buf && pitchF
string num = buf.str();
putText(originalWave, num, Point(start * MAXLENGTH / dataLength, 30), FONT_HERSHEY_SIMPLEX, 0.7, Scalar(0, 0, 255), 2);
imshow(&originalWave&, originalWave);
// show current frame in zoom out model
Mat oneSelectF
wav2image(oneSelectFrame, wavFrame, 0, wavFrame.size(), 400);
imshow(&oneSelectFrame&, oneSelectFrame);
if (!frames)
while (waitKey(30) != ' ');
waitKey(50);
cout&&&Num of frames is: &&&frames&&
/******************* Calculate all frame part End ***************/
// show all pitch frequency before smooth
Mat showAllPitchF
wav2image(showAllPitchFre, allPitchFre, 0, allPitchFre.size(), 400);
putText(showAllPitchFre, &Before smooth&, Point(10, showAllPitchFre.rows - 20), FONT_HERSHEY_SIMPLEX, 1, Scalar(60, 200, 255), 1);
imshow(&showAllPitchFre&, showAllPitchFre);
/******************* Smooth by medium filter part Start **************/
int kernelSize = 5;
vector&short& afterMedF
short sum(0);
afterMedFilter.assign(allPitchFre.size(), allPitchFre[0]);
for (int k = cvFloor(kernelSize/2); k & allPitchFre.size(); k++)
vector&short& kernelD
for (int i = -cvFloor(kernelSize/2); i & cvCeil (kernelSize/2); i++)
kernelData.push_back(allPitchFre[k+i]);
nth_element(kernelData.begin(), kernelData.begin() + cvCeil (kernelSize/2), kernelData.end());
afterMedFilter[k] = kernelData[cvCeil (kernelSize/2)];
sum += afterMedFilter[k];
cout&&afterMedFilter[k]&&
// show all pitch frequency and mean pitch frequency after smooth
Mat showAfterMedF
wav2image(showAfterMedFilter, afterMedFilter, 0, afterMedFilter.size(), 400);
putText(showAfterMedFilter, &After smooth&, Point(10, showAfterMedFilter.rows - 20), FONT_HERSHEY_SIMPLEX, 1, Scalar(60, 200, 255), 1);
short mean = sum / (afterMedFilter.size() - cvFloor(kernelSize/2));
writeFile&&&The mean pitch frequency is: &&&mean&&
string num = &Mean: & + buf.str() + &Hz&;
putText(showAfterMedFilter, num, Point(10, 40), FONT_HERSHEY_SIMPLEX, 1, Scalar(255, 200, 255), 2);
imshow(&showAfterMedFilter&, showAfterMedFilter);
/******************* Smooth by medium filter part End ***************/
while (waitKey(30) != 27);
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6727378次
积分:26877
积分:26877
排名:第166名
原创:116篇
转载:11篇
评论:3569条
关注:机器学习、计算机视觉、人机交互和人工智能等领域。
交流请发邮件,不怎么看博客私信^-^
(4)(2)(1)(1)(2)(2)(1)(7)(5)(4)(4)(9)(2)(6)(1)(10)(5)(8)(14)(7)(8)(25)下载作业帮安装包
扫二维码下载作业帮
1.75亿学生的选择
泛音,基音的解释与关系最好以钢琴或吉他为例解释一下
  就是在吉他泛音品位上面,用左手手指虚按着弦,也就是轻放在上面别按下去,然后在右手弹的时候左手放开,如果你一时不能马上练会,那你就先弹闷音吧,闷音能弹出来了以后,再在右手弹奏时同时放开左手,左右手配合的时间差不同弹奏出的泛音效果也不同  朋友,你对泛音的理解还不正确,如果直接弹空弦音,那么弦的震动就会包括基音和泛音了,泛音在弦不同处的音高是不同的,泛音的多少和强度很大程度决定了音色,但是平时泛音都会被基音所掩盖,所以你可能没有泛音的直观感受.  在12品处不用按弦而产生的泛音叫自然泛音,它的方法是:左手手指指肚轻触12品处的琴弦,并不按下,右手拨弦的同时,放开左手手指,产生类似钟鸣的声音,清亮、带有金属感.如果你还没有这个概念,你可以下载 汪峰的“花火”这首歌,它前奏一开始就是连续的泛音演奏,可以以此作为参考!  自然泛音产生的重点是左右手配合的时机,左手快了,出来的是空弦音,左手慢了,出来的是闷音,所以只能自己琢磨和试验,仅凭文字很难描述了.  多试试,多练练,说不定一次就成功了呢!  一般来讲,如果是民谣吉他,基本上使用自然泛音,一般在5品、7品、12品处,左手手指轻触琴弦5品、7品、或12品其中之一的位置(记着是在品柱的正上方).右手拨弦的同时,左手手指放开,就会听到一种很特别的声音,这就是泛音了.  强烈建议听听罗大佑的《乡愁四韵》,你就明白了,这首歌的吉他用了很多的泛音,5品、7品、12品的都有.开头就是12品处的泛音.认真听听,再自己试试,应该就能弄明白了.  自然泛音可以在有泛音点的品柱正上方用手指虚按,拨片弹后左手放开,弹人工泛音拨片要拿的浅一点,拨片下拨的时候,用拿拨片的大拇指侧蹭一下弦,具体位置要在琴弦震动有效长度的2分之一,3分之一,4分之一...这个要经过大量的训练掌握弹奏人工泛音的位置,一般会把档位放在后拾音器上,点弦泛音,用食指虚按泛音点的品柱正上方,大拇指拨弦
为您推荐:
其他类似问题
扫描下载二维码

我要回帖

更多关于 求解释 的文章

 

随机推荐