谱减法原理及源代码实现
- 格式:docx
- 大小:15.55 KB
- 文档页数:3
基于谱减法开题报告基于谱减法开题报告一、研究背景谱减法是一种常见的语音信号处理方法,用于降噪和增强语音信号的质量。
在实际应用中,语音信号常常受到噪声的干扰,影响了语音识别、语音合成等领域的性能。
因此,研究如何有效地去除噪声,提升语音信号的质量具有重要的实际意义。
二、研究目的本研究旨在探索和改进谱减法的方法,提高语音信号降噪的效果。
通过对语音信号的频谱进行分析和处理,去除噪声成分,保留语音信号的主要特征,从而提升语音信号的清晰度和可识别性。
三、研究内容及方法1. 语音信号的特征提取首先,需要对语音信号进行特征提取,以便更好地理解信号的频谱特性。
常用的特征提取方法包括短时傅里叶变换(STFT)、梅尔倒谱系数(MFCC)等。
在本研究中,将采用STFT方法对语音信号进行频谱分析,并提取相关特征。
2. 噪声模型的建立为了更好地理解和处理噪声,需要建立一个准确的噪声模型。
噪声模型可以通过采集和分析真实环境中的噪声数据得到,也可以通过合成噪声来模拟。
在本研究中,将采用合成噪声的方法建立噪声模型,并对其进行分析和优化。
3. 谱减法的改进谱减法是一种基本的降噪方法,通过对信号的频谱进行减法运算,去除噪声成分。
然而,传统的谱减法存在一些问题,如信号失真、语音信息丢失等。
因此,本研究将对谱减法进行改进,以提高降噪效果。
4. 实验设计与评估为了验证改进后的谱减法的效果,需要设计一系列实验,并进行评估。
实验可以采用真实语音数据和合成噪声数据,通过比较降噪前后的信噪比(SNR)和语音质量评分等指标,来评估改进后的方法的性能。
四、研究意义和预期结果本研究的意义在于提高语音信号降噪的效果,为语音识别、语音合成等领域的应用提供更清晰、更可靠的语音信号。
预期结果是通过改进谱减法的方法,降低噪声对语音信号的影响,提升语音信号的质量和可识别性。
五、研究计划与进度安排1. 数据采集与准备:收集和准备真实语音数据和合成噪声数据。
2. 特征提取与噪声模型建立:对语音信号进行特征提取,并建立准确的噪声模型。
谱减法门限系数
谱减法是一种音频降噪的方法,它适用于在强噪声环境下对语音信号的处理。
谱减法会对输入信号的频谱进行分析,然后根据门限系数来判断哪些频率可以被保留,哪些频率可以被去除,进而实现音频的降噪。
而门限系数是在进行谱减法处理时必须要设置的参数。
下面就来详细介绍一下门限系数:
1. 什么是门限系数?
门限系数指的是在进行音频谱减法降噪处理时所设置的一个阈值,它用来控制那些信号频率可以消除,那些信号频率可以保留。
门限系数越大,保留的频率就越多,消除的噪声信号就越少,同时可能会导致语音信号被误判为噪声而消除;而门限系数越小,则会有更多的噪声信号被消除,但也可能会一并消除一些语音信号,从而影响语音的质量。
2. 如何设置门限系数?
门限系数的设置需要在实际处理中进行调试。
通常的方法是通过不同的输入音频样本进行测试,逐渐确定最佳的门限系数。
另外,不同的噪声环境也需要根据具体情况进行不同的门限系数设置。
在设置时也需要注意避免过高或者过低的门限系数,以免影响音频质量。
3. 门限系数的影响因素有哪些?
门限系数的大小会影响音频效果,但是门限系数的设置并不是唯一的
影响因素。
除了门限系数之外,还有其他因素也会对音频效果产生影响。
比如,正确的频域处理方式、处理频域的窗长、噪声估计结果的准确性等等,都会对音频处理的效果产生影响。
总的来说,门限系数作为谱减法的一个必要参数,在进行音频降噪处理时,需要根据具体情况进行合理的设置。
合理的设置门限系数有助于实现更好的音频降噪效果。
plc减法指令PLC减法指令PLC(可编程逻辑控制器)是一种用于自动化控制的电子设备,它可以通过编程实现各种逻辑运算和控制操作。
在PLC编程中,减法指令是常用的一种指令类型。
本文将详细介绍PLC减法指令的相关内容。
一、PLC减法指令概述在PLC编程中,减法指令是用于实现两个数值相减的操作。
通常情况下,这两个数值可以来自于不同的输入信号或者寄存器数据。
根据不同的PLC型号和厂家,减法指令可能会有所差异,但基本原理都是相同的。
二、PLC减法指令语法格式在PLC编程中,减法指令通常采用以下语法格式:SUB destination, source其中,“destination”表示被减数存储地址或者寄存器地址,“source”表示减数存储地址或者寄存器地址。
需要注意的是,在不同的PLC编程软件中,“destination”和“source”的顺序可能会有所不同。
三、PLC减法指令使用示例下面通过一个简单的示例来说明如何使用PLC减法指令。
假设我们需要实现一个简单的计数器功能,当输入信号A为1时,计数器加1;当输入信号B为1时,计数器减1。
此时可以使用PLC减法指令来实现计数器的减法操作。
具体实现方法如下:1. 将计数器的初始值存储在一个寄存器中。
2. 当输入信号A为1时,使用PLC加法指令将计数器寄存器中的值加1。
3. 当输入信号B为1时,使用PLC减法指令将计数器寄存器中的值减1。
4. 将计数器寄存器中的最新值输出到显示屏或者其他设备上。
四、PLC减法指令注意事项在使用PLC减法指令时,需要注意以下几个问题:1. 确保被减数和减数的数据类型相同。
如果数据类型不同,则需要进行数据类型转换。
2. 确保被减数和减数的数据范围符合要求。
如果数据范围超出了PLC 所支持的范围,则可能会导致运算结果不正确或者程序崩溃。
3. 在进行多次连续的加/减操作时,需要考虑运算顺序和优先级。
通常情况下,先进行乘/除运算,再进行加/减运算。
谱减法实验心得谱减法是一种常用的语音增强技术,通过对语音信号进行频域处理,将噪声部分从语音信号中减去,以提高语音信号的清晰度和可听性。
我在实验室进行了一次谱减法实验,并且总结出了一些心得体会。
首先,实验前要对谱减法的原理进行充分理解。
谱减法是通过对语音信号进行短时傅里叶变换,将语音信号转化到频域,然后对频域信号进行处理,去除噪声成分。
理解了这个原理,对于实验的进行会有很大帮助。
其次,实验中选择合适的参数非常重要。
谱减法中有很多参数可以调节,如窗长、窗移、谱平滑参数等。
这些参数的选择直接影响着最终的语音增强效果。
实验中我进行了多轮参数调节和实验比较,最终选择了窗长为30ms,窗移为10ms,谱平滑参数为1。
这个参数组合在我实验数据集上获得了最好的效果。
再次,实验中要注意对比实验结果。
在进行谱减法实验时,要对比处理前后的语音信号,以及处理前后的语音信噪比和信号失真情况。
只有通过对比才能真正评估谱减法的效果。
在实验中,我分别记录了处理前后的语音信号,并使用信噪比和信号失真度来评估谱减法的效果。
通过对比实验结果,可以明显看到谱减法对于语音信号的增强效果。
另外,实验中要注意实验数据集的选择。
实验数据集的选择应该具有代表性,并且包含不同的噪声类型和强度。
只有在具有代表性的数据集上进行实验才能得到具有普适性的实验结果。
在我实验中,我选择了包含了多种噪声类型(如白噪声、车流噪声、人声噪声等)和噪声强度的语音数据集,以确保实验结果的可靠性和有效性。
最后,实验中要对谱减法的局限性有所了解。
尽管谱减法在语音增强领域有着广泛应用,但是它也存在一些局限性。
例如,谱减法对于非稳态噪声效果不佳,同时谱减法在增强语音信号的同时也会引入一定的失真。
因此,在实际应用中,需要根据具体情况和需求选择合适的语音增强方法。
通过这次实验,我对谱减法有了更深入的了解,并且掌握了一些实验技巧。
谱减法是一种有效的语音增强方法,在实际应用中具有重要的意义。
⼏种改进的谱减算法简介⾮线性谱减Berouti等⼈提出的谱减算法,假设了噪声对所有的频谱分量都有同等的影响,继⽽只⽤了⼀个过减因⼦来减去对噪声的过估计。
现实世界中的噪声并⾮如此,这意味着可以⽤⼀个频率相关的减法因⼦来处理不同类型的噪声。
多带谱减法在多带算法中,将语⾳频谱划分为N个互不重叠的⼦带,谱减法在每个⼦带独⽴运⾏。
将语⾳信号分为多个⼦带信号的过程可以通过在时域使⽤带通滤波器来进⾏,或者在频域使⽤适当的窗。
通常会采⽤后⼀种办法,因为实现起来有更⼩的运算量。
多带谱减与⾮线性谱减的主要区别在于对过减因⼦的估计。
多带算法针对频带估计减法因⼦,⽽⾮线性谱减算法针对每⼀个频点,导致频点上的信噪⽐可能有很⼤变化。
这种剧烈变化是谱减法中所遇到的语⾳失真(⾳乐噪声)的原因之⼀。
相反,⼦带信噪⽐变化则不会特别剧烈。
MMSE谱减算法上⾯的⽅法中,谱减参数alpha和beta通过实验确定,⽆论如何都不会是最优的选择。
MMSE谱减法能够在均⽅意义下最优地选择谱减参数。
具体请参考论⽂:A parametic formulation of the generalized spectral subtractor method扩展谱减法基于⾃适应维纳滤波与谱减原理的结合。
维纳滤波⽤于估计噪声谱,然后从带噪语⾳信号中减去该噪声谱。
具体请参考以下两篇论⽂:Extended Spectral Substraction:Description and Preliminary Results.Extended Spectral Substraction⾃适应增益平均的谱减谱减法中导致⾳乐噪声的两个因素在于谱估计的⼤范围变化以及增益函数的不同。
对于第⼀个问题,Gustafsson等⼈建议将分析帧划分为更换⼩的⼦帧以得到更低分辨率的频谱。
⼦帧频谱通过连续平均以减⼩频谱的波动。
对于第⼆个问题Gustafsson等⼈提出使⽤⾃适应指数平均,在时间上对增益函数做平滑。
快速傅里叶变换(FFT)算法原理及代码解析•FFT与DFT关系:快速傅里叶变换(Fast Fourier Transform)是离散傅里叶(DFT)变换的一种快速算法,简称FFT,通过FFT可以将一个信号从时域变换到频域;FFT(快速傅里叶变换)其本质就是DFT,只不过可以快速的计算出DFT结果,它只是傅立叶变换算法实现过程的一种改进。
要弄懂FFT,必须先弄懂DFT,DFT(DiscreteFourier Transform) 离散傅里叶变换的缩写,咱们先来简单讨论一下DFT。
DFT(FFT)的作用:可以将信号从时域变换到频域,而且时域和频域都是离散的,通俗的说,可以求出一个信号由哪些正弦波叠加而成,求出的结果就是这些正弦波的幅度和相位。
•DFT的公式:其中X(k)表示DFT变换后的数据,x(n)为采样的模拟信号,公式中的x(n)可以为复信号,实际当中x(n)都是实信号,即虚部为0,此时公式可以展开为:那么,对于一个的序列进行不断分解,就可以得出如下所谓的蝶形图:•FFT处理蝶形运算蝶形运算的规律:同一级中所有蝶形的输入点在同一竖直线上,意味着我们可以按级来运算,对于M级的蝶形,编个M次循环就好了;所有数据点在运算后不会窜位,即计算后可以将结果存入原来的地址空间。
每级N/2个蝶都需要用到系数WN,这里称它为旋转因子。
我们来观察旋转因子WN的规律。
以8点的蝶形图为例:可见,第L级的旋转因子为:可以看到,每个蝶的两个输入点下标跨度是不一样的。
比如第一级中是相邻两个数据作蝶运算,第二级中是两个输入点隔开一个点,而第三级隔开三个点。
不难找到规律:第L级中,第二个输入点的坐标是第一个点的坐标+space,space=Math.Pow(2, L)=num。
FFT的算法是写一个三重循环:•第一重循环对每一级运算(每级含num=Math.Pow(2, L)个蝶形);•第二重对每一个旋转因子对应的蝶运算,那么有几个蝶呢?很简单,每级都应该有N/2个蝶,而每个因子对应N/2 / num个蝶;•第三重循环对每个蝶进行计算,需要注意的一是循环下标起始点的位置,二是每次计算需要申明临时变量来保存输入数据点。
摘要摘要:在我们的日常交流和语音通信系统中,加性宽带噪声严重影响了语音质量和可懂度。
从带噪语音中提取原始语音信号的方法很多,在单信道条件下,减谱算法以其运算量小、原理简单、易于实现并且有不错的增强效果而得到了广泛的应用。
减谱语音增强算法的核心是噪声检测和减谱规则。
在分析了语音增强算法理论的基础上,本文首先研究了语音激活检测算法。
对基于短时能量和短时过零率双门限法语音激活检测的噪声估计算法做了研究及仿真,同时还研究了一种基于最小子带能量的噪声估计方法。
然后,通过分析经典减谱法的原理及其一般改进形式,研究了一种基于噪声残差的谱相减改进算法和一种可以不以噪声是零均值的高斯分布为前提的减谱法改进算法。
最后通过大量的仿真实验,验证了所研究的几种改进算法都能有效地提高增强效果。
关键词:减谱法;语音增强;语音激活检测;噪声估计ABSTRACTABSTRACT: In our daily conversation and speech communication system, the additive broadband noise has badly impact on the qualification and the intelligibility of the speech. There are many methods to pick-up the pure speech signal from noisy speech signal. Under the condition of single channel, spectral subtraction speech enhancement algorithm has been widely used because it has many advantages,such as the calculation is small, the theory is simple, and the implement is easy.The main idea of the spectral subtraction algorithm is noise detection and spectral subtraction rule. Firstly, voice activity detection algorithm is discussed in this paper. We research and simulate the voice activity detection based on short-time energy and short-time zero crossing rate and research a noise estimate method based on minimum subband energy. Then, after analyzing the conventional spectral subtraction algorithm and its improved form, we study the improved spectral subtraction algorithm based on noise residual error and research another improved spectral subtraction algorithm without Gauss noise. Finally, many experimental results show that all these improved algorithms can improve the quality of the speech effectively.Keywords: spectral subtraction; speech enhancement; voice activity detection; noise estimation目录摘要 (I)ABSTRACT .............................................................................................. I I 第1章绪论 (1)1.1 课题的研究背景 (1)1.2 语音增强技术发展现状况 (2)1.3 本文结构安排 (4)第2章语音增强算法基础理论 (5)2.1 人耳感知特性 (5)2.2 语音产生及其特性分析 (5)2.2.1 语音信号的声学基础和产生模型 (5)2.2.2 语音特性分析 (6)2.3 噪声分类及其特性 (7)2.4 语音信号的短时处理 (8)2.5 语音增强性能 (8)2.6 本章小结 (10)第3章语音激活检测 (11)3.1 引言 (11)3.2 基于短时能量和短时过零率的语音激活检测算法 (12)3.2.1 短时能量 (12)3.2.2 短时过零率 (13)3.2.3 短时能量和短时过零率双门限算法 (13)3.3 实验仿真 (15)3.4 本章小结 (16)第4章噪声参数的估计 (17)4.1 引言 (17)4.2 传统减谱法中所使用的噪声参数估计 (17)4.2.1 传统减谱法中噪声参数估计的原理 (17)4.2.2 传统减谱法中噪声参数估计的步骤 (17)4.2.3 传统减谱法中噪声参数估计的缺点 (18)4.3 一种改进的背景噪声检测算法 (18)4.3.1 算法的数学模型 (19)4.3.2 算法原理 (19)4.3.3 算法的实现流程 (20)4.4 本章小节 (21)第5章减谱算法的具体研究 (23)5.1 概述 (23)5.2 传统减谱算法 (23)5.2.1 功率减谱的原理 (23)5.2.2 幅值减谱的原理 (24)5.2.3 减谱经典形式的实现流程 (25)5.2.4 减谱经典形式的缺点 (26)5.3 传统减谱算法的改进算法的研究 (26)5.3.1 普通减谱法的基本改进形式 (26)5.3.2 基于噪声残差的减谱改进算法 (27)5.3.3 一种从不同角度改进的减谱改进算法分析 (28)5.4 本章小节 (30)第6章算法MATLAB实现以及增强效果分析 (31)6.1 在MATLAB下实现程序的优缺点 (31)6.1.1 MATLAB实现的优势 (31)6.1.2MATLAB实现的缺点 (32)6.2经典减谱算法及几种改进算法的MATLAB实现 (33)6.2.1 经典减谱算法的MATLAB仿真 (33)6.2.2减谱法基本改进形式的MATLAB仿真与分析 (34)6.2.3 基于噪声残差的改进算法的MATLAB仿真与分析 (36)6.2.4 减谱改进形式3的MATLAB仿真与分析 (39)6.3 几种减谱改进算法的性能对比 (42)6.4 本章小节 (44)第7章总结 (45)7.1 本文的主要工作 (45)7.2 存在的问题以及今后的目标 (45)参考文献 (47)致谢 (48)附录 (49)第1章绪论1.1 课题的研究背景语音通信是一种理想的人机通信方式。
逆波兰(加、减、乘、除、括号)表达式原理及C++代码实现当我们输⼊⼀个数学表达式,是中缀表达式,我们⾸先转换为后缀表达式(逆波兰表达式),然后再进⾏求值。
代码思路:(1)⾸先对输⼊的中缀表达式合法性进⾏判断,bool isStringLegal(const char* str); 函数实现。
(2)然后把中缀表达式转换为后缀表达式。
(3)根据后缀表达式求出结果,double getTheResult(vector<string> &vec);函数实现。
注意:表达式的运算符可以输⼊加、减、乘、除、括号,输⼊的数据为整形数据,计算结果为double型数据。
1 #include <iostream>2 #include <math.h>3 #include <map>4 #include <vector>5 #include <string.h>6 #include <memory>7 #include <string>8 #include <stdio.h>9 #include <stack>10 #include <stdlib.h>1112using namespace std;1314#define MAX_STRING_LENGTH 1001516/* 解析当前的整形数据,并把整形数据转换为string型 */17string analyData(const char* str, int &i);1819/* 根据逆波兰表达式求表达式的值 */20double getTheResult(vector<string> &vec);2122/* 判断该字符是否是 + - * / ( ) */23bool isCalChar(const char ch);2425/* 判断输⼊的中缀表达式是否合法 */26bool isStringLegal(const char* str);27282930/* 解析当前的整形数据,并把整形数据转换为string型 */31string analyData(const char* str, int &i)32 {33int temp = i++;34while(str[i] >= '0' && str[i] <= '9' && str[i] != '\0')35 {36 i++;37 }3839string s(str+temp,str+i);4041return s;42 }4344/* 根据逆波兰表达式求表达式的值 */45double getTheResult(vector<string> &vec)46 {47 vector<string>::iterator it;48 stack<double> sta;4950string strTemp;51double d = 0, d1 = 0, d2 = 0;5253for(it = vec.begin(); it != vec.end(); it++)54 {55 strTemp = (*it);5657if(strTemp == "+")58 {59 d1 = sta.top();60 sta.pop();6162 d2 = sta.top();63 sta.pop();6465 d = d1 + d2;66 sta.push(d);67 }68else if(strTemp == "-")69 {70 d1 = sta.top();71 sta.pop();7273 d2 = sta.top();74 sta.pop();7576 d = d2 - d1;77 sta.push(d);78 }79else if(strTemp == "*")80 {81 d1 = sta.top();82 sta.pop();8384 d2 = sta.top();85 sta.pop();8687 d = d2 * d1;88 sta.push(d);89 }90else if(strTemp == "/")91 {92 d1 = sta.top();93 sta.pop();9495 d2 = sta.top();96 sta.pop();9798 d = d2 / d1;99 sta.push(d);100 }101else102 {103const char *p = strTemp.c_str();104 d = atoi(p);105 sta.push(d);106 }107 }108return sta.top();109 }110111/* 判断该字符是否是 + - * / ( ) */112bool isCalChar(const char ch)113 {114if(ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')') 115 {116return true;117 }118119return false;120 }121/* 判断输⼊的中缀表达式是否合法 */122bool isStringLegal(const char* str)123 {124/* 判断是否是空串 */125if(NULL == str)126 {127return false;128 }129130int len = strlen(str);131int i = 0;132int flag = 0;133134/* 字符串的开头和末尾是否是数字 */135if(str[0] > '9' || str[0] < '0' || str[len-1] > '9' || str[len-1] < '0')136 {137return false;138 }139140141for(i = 0; str[i] != '\0'; i++)142 {143/* 是否有除了加减乘除括号之外的字符 */144if(isCalChar(str[i]) == false)145 {146return false;147 }148149/* 判断是否有两个连续的符号 */150if(i < len-1 && isCalChar(str[i]) == true)151 {152if(isCalChar(str[i+1]) == true)153 {154return false;155 }156157 }158159/* 判断括号是否成对 */160if(str[i] == '(')161 {162 flag++;163 }164else if(str[i] == ')')165 {166 flag--;167 }168169/* 判断是否出现 )( 这样的情况 */170if(flag < 0)171 {172return false;173 }174 }175176/* 判断括号是否匹配 */177if(flag != 0)178 {179return false;180 }181182return true;183 }184185int main(void)186 {187char str[MAX_STRING_LENGTH] = {0};188int i = 0;189string data;190191/* 存放运算符表达式的栈 */192 stack<char> oper_char;193194/* 存放后缀表达式 */195 vector<string> post_str;196197/* 输⼊中缀的表达式 */198 gets(str);199200/* 判断输⼊的中缀表达式是否合法 */201if(isStringLegal(str) != true)202 {203 cout << "This expression is not legal." << endl; 204 }205else206 {207/* 将中缀表达式转换为后缀表达式 */208for(i = 0; str[i] != '\0'; i++)209 {210/* 如果该字符为数字,解析该数字,并压⼊栈 */ 211if(str[i] >= '0' && str[i] <= '9')212 {213 data = analyData(str,i);214 post_str.push_back(data);215 i--;216 }217else if(str[i] == '(')218 {219 oper_char.push(str[i]);220 }221else if(str[i] == ')')222 {223char chtemp[2] = {0};224225 chtemp[0] = oper_char.top();226227while(chtemp[0] != '(')228 {229string strtemp(chtemp);230 post_str.push_back(strtemp);231 oper_char.pop();232233 chtemp[0] = oper_char.top();234 }235 oper_char.pop();236 }237else if(str[i] == '+' || str[i] == '-')238 {239char chtemp[2] = {0};240241/* 全部出栈,但是碰到 '('就要停⽌出栈 */242while(oper_char.size() != 0)243 {244 chtemp[0] = oper_char.top();245if(chtemp[0] == '(')246 {247break;248 }249250 oper_char.pop();251252string strtemp(chtemp);253 post_str.push_back(strtemp);254 }255256/*将当前的表达式符号⼊栈*/257 oper_char.push(str[i]);258 }259else if(str[i] == '*' || str[i] == '/')260 {261char chtemp[2] = {0};262while(oper_char.size() != 0)263 {264 chtemp[0] = oper_char.top();265if(chtemp[0] == '(' || chtemp[0] == '+' || chtemp[0] == '-') 266 {267break;268 }269else270 {271 oper_char.pop();272273string strtemp(chtemp);274 post_str.push_back(strtemp);275 }276 }277278/*将当前的表达式符号⼊栈*/279 oper_char.push(str[i]);280 }281 }282283/* 存放表达式的栈可能还有数据 */284while(!oper_char.empty())285 {286char chtemp[2] = {0};287 chtemp[0] = oper_char.top();288 oper_char.pop();289290string strtemp(chtemp);291 post_str.push_back(strtemp);292 }293294/* 把逆波兰表达式求值 */295 cout << getTheResult(post_str) << endl;296 }297298return0;299 }。
23456
处理宽带噪声的最通用技术是谱减法。它利用语音信号的短时平稳特性,从带噪语音的短时
谱值中减去噪声的短时谱,从而得到纯净语音的频谱,达到语音增强得目的。谱减法包括幅
度谱减法和功率谱减法:幅度谱减法就是在频域中从带噪语音的幅度谱上减去噪声的幅度谱
作为语音信号的幅度谱;功率谱减法则是从带噪语音的功率谱中减去噪声的功率谱,得到纯
净语音的功率谱估计,通过开方运算得到幅度谱。由于人耳对语音频谱分量的相位感知不敏
感,因此这些算法都是在幅度上进行的修正,相位部分则保持不变,仍然使用带噪语音的相
位。
谱减法通过从带噪语音的短时谱估值中减去噪声的短时谱来达到语音增强得目的,算法简单
且容易实现。但在减去噪声谱后,还会有些较大功率谱分量的剩余部分,在频谱上呈现出随
机出现的尖峰,在听觉上形成残留噪声。这种噪声具有一定的节奏性起伏感,被称之为“音
乐噪声”。后来,Ephraim 等人又对谱减法进行了大量改进,部分解决了“音乐噪声”问题,
但在带噪语言信噪比较低时其残余噪声还是很大,尤其是当信噪比小于 5dB 的时候。因此,
如何最大限度地消除谱减法中的“音乐噪声”,仍将是人们今后研究的重要课题。
以下为MATLAB源码的实现
%基本谱减法
clear;
%[xx,fs]=wavread('E:\mywhisper\shu.wav');
%[xx,fs]=wavread('E:\speech\x\w1xun_01.wav');
%[xx,fs]=wavread('E:\speech\耳语音切割\b\w1ba_5');
[xx,fs]=wavread('MIC0.wav');% 读取音频文件yuan.wav,并返回采样数据给变量xx及采样率
Fs
[team,row]=size(xx);%将数组xx的行数赋给team,列数赋给row
if row==2
x=(xx(:,1)+xx(:,2))/2;
yy=x;
%如果语音信号xx为2列,即信号为双声道,则将其转换成单声道信号,即取两列的平均
值赋给x,并将x的值赋给yy
else
x=xx;
yy=x;
%若语音信号xx为单声道,则将xx的值赋给x,并将x的值赋给yy
end
x=x-mean(x)+0.1*rand(length(x),1);
N=length(x);%将语音信号长度赋给变量N
n=220;%对语音信号进行分帧,帧长为220
n1=160;%帧移为160
frame=floor((N-n)/(n-n1));%将分帧数赋给变量frame
%frame=floor(N/n);
for i=1:frame
y1=x((i-1)*(n-n1)+1:(i-1)*(n-n1)+n).*hamming(n);
%对每段分帧进行加窗处理
fy=fft(y1,n);
nen(i,:)=abs(fy).^2;% 将频域信号功率赋给矩阵变量nen
23456
ang(i,:)=angle(fy);%将频域信号的相位角赋给矩阵变量ang
end
yuzhi=sum(sum(nen(2:5,:)))/(4*n);
for i=1:frame
nen(i,:)=nen(i,:)-yuzhi;
nen(i,find(nen(i,:)<0))=0;
%chuli=nen(i,1:n/2);
%chuli=chuli-yuzhi;
%chuli(find(chuli<0))=0;
%nen(i,:)=[chuli,fliplr(chuli)];
% nen(i,:)=filter(1,[0.5 0.5],nen(i,:));
% nen(i,find(nen(i,:)<0))=0;
end
for i=1:frame
nen(i,:)=sqrt(nen(i,:));%将纯语音功率谱开根,得到频域值
jie=nen(i,:).*exp(j*ang(i,:));
out(i,:)=real(ifft(jie))/hamming(n)'; %对纯语音频谱进行逆傅里叶变换,并取其实部,并进
行去窗处理
end
zong=out(1,:)';%将第一帧中未重叠部分记入数组zong
jiewei=n;
for i=2:frame
zong(jiewei-n1+1:jiewei)=(zong(jiewei-n1+1:jiewei)+out(i,1:n1)')/2;
jiewei=jiewei+n-n1;% 使指针jiewei依次指向下一帧的帧尾
zong=[zong;out(i,n1+1:end)'];%将从第二帧开始的每一帧中未重叠部分记入数组zong
end
%zong=out(1,:)';
%for i=2:frame
%zong=[zong;out(i,:)'];
%end
%
%for i=1:frame
% zong=[zong,nen(i,:)'];
% zong(i*(n-n1)+1:(i-1)*(n-n1)+n)=zong(i*(n-n1)+1:(i-1)*(n-n1)+n)/2;
figure(1); %创建图1
subplot(211); %把图形窗口分成2*1个小窗口,取第1个小窗口
plot(x);%以数组x绘图基本二维曲线
axis([1,(n-n1)*frame+n,min(x),max(x)]);% 对当前二维图形对象的X轴和Y轴进行标定,x轴的
范围为1到最后一个分帧结尾,y轴的范围为带噪语音时域最小值到最大值
subplot(212); %把图形窗口分成2*1个小窗口,取第2个小窗口
specgram(x,fs,1024,n,n1);%画出语音的语谱图
figure(2); %创建图2
subplot(211); %把图形窗口分成2*1个小窗口,取第1个小窗口
plot(zong); %以数组zong绘图基本二维曲线
axis([1,(n-n1)*frame+n,min(zong),max(zong)]); % 对当前二维图形对象的X轴和Y轴进行标定,
23456
x轴的范围为1到最后一个分帧结尾,y轴的范围为纯语音时域最小值到最大值
subplot(212); %把图形窗口分成2*1个小窗口,取第2个小窗口
specgram(zong,fs,1024,n,n1); %画出语音的语谱图
wavplay(x,fs);%播放单声道带噪语音音频
wavplay(zong,fs);%播放单声道纯净语音音频