python语音识别分析_python数据建模分析 - 语音识别

Getting Started!首先,我们要知道语音的产生过程

voice.png

状态:由肺产生向外的气流,完全放松时声带张开,就是平时的呼吸。如果声带一张一合(振动)形成周期性的脉冲气流。这个脉冲气流的周期称之为——基音周期(题主所言因音色不同导致的频率不同,事实上音色的大多是泛频上的差异,建立在基频之上,这个基频就是基音周期了,泛频可以忽略)。当然啦,这只是在发浊音(b,d,v...)时才会有,当发出清音(p,t,f...)时声带不振动,但是会处于紧绷状态,当气流涌出时会在声带产生湍流。清音和浊音是音素的两大类。接下来脉冲气流/湍流到达声道,由声道对气流进行调制,形成不同的音素。多个音素组成一个音节(就汉语而言是[声母]+韵母)。如果没学过信号系统那就想像一下平舌音和翘舌音,z和zh发声时肺和喉的状态都一样,只是舌头动作不一样,发出的声音也就不一样了,这就算是简单的调制。从而声音的波形会发生一些变化。这个波形,就是以后分析所需要的数据。

频谱图

时谱图

语谱图

以千里码 语音识别-1为例,将Mp3文件转换成wav,分析其频谱图

参照wav使用手册,让我们介绍一下wav文件

WAV是Microsoft开发的一种声音文件格式,虽然它支持多种压缩格式,不过它通常被用来保存未压缩的声音数据(PCM脉冲编码调制)。WAV有三个重要的参数:声道数、取样频率和量化位数。

声道数:可以是单声道或者是双声道

采样频率:一秒内对声音信号的采集次数,常用的有8kHz, 16kHz, 32kHz, 48kHz, 11.025kHz, 22.05kHz, 44.1kHz

量化位数:用多少bit表达一次采样所采集的数据,通常有8bit、16bit、24bit和32bit等几种

1.读入二进制音频流数据流程

对于一个音频实例wf而言,通过调用它的方法读取WAV文件的格式和数据:getnchannels, getsampwidth, getframerate, getnframes等方法可以单独返回WAV文件的特定的信息。

readframes:读取声音数据,传递一个参数指定需要读取的长度(以取样点为单位),readframes返回的是二进制数据

PS:注意需要使用"rb"(二进制模式)打开文件

import wave

import pyaudio

import numpy

from matplotlib import pylab

#打开wav文档,文件路径根据需要修改

wf = wave.open("F:\\work\\war.wav","rb")

#创建PyAudio对象

p = pyaudio.PyAudio()

class Audio(object):

def __init__(self):

self.channels = wf.getnchannels()

# 返回音频通道数

self.rate = wf.getframerate()

# 返回采样频率。

self.format = p.get_format_from_width(wf.getsampwidth())

# 返回指定宽度的PortAudio格式常量。

self.stream = p.open(format=self.format,channels=self.channels,rate=self.rate,output=True)

# 使用所需的音频参数在所需设备上打开一个流

self.nframes = wf.getnframes()

# 返回音频帧数

self.collect_point_num = 44100

# 采样点数,修改采样点数和起始位置进行不同位置和长度的音频波形分析

self.start = 0

# 开始采样位置

def read_data(self):

self.str_data = wf.readframes(self.nframes)

# 读取声音数据,传递一个参数指定需要读取的长度(以取样点为单位),readframes返回的是二进制数据(即bytes数组)

# print(self.str_data)

wf.close()

#关闭媒体流

if __name__ == '__main__':

aduio = Audio()

aduio.read_data()

python output

aduio.jpg

2.生成的流媒体字节数组计算出每个取样的时间

将读取的二进制数据转换为一个可以计算的数组

通过fromstring函数将字符串转换为数组,通过其参数dtype指定转换后的数据格式,由于我们的声音格式是以两个字节表示一个取样值,因此采用short数据类型转换。现在我们得到的wave_data是一个一维的short类型的数组,但是因为我们的声音文件是双声道的,因此它由左右两个声道的取样交替构成:LRLRLRLR....LR(L表示左声道的取样值,R表示右声道取样值)'

由帧率的计算公式:

采样率 = 每秒中的采样频率/每秒中的采样点数 帧率(fps) =1 /采样率

将波形数据转换为数组

通过取样点数和取样频率计算出每个取样的时间

def convrt_data(self):

self.df = self.rate / (self.collect_point_num - 1)

# 根据总平均法使用全局帧数除以全局时间,以求出帧率

def Data_collection(self):

wave_data = numpy.fromstring(self.str_data,dtype=numpy.short)

# 根据声道数和量化单位,将读取的二进制数据转换为一个可以计算的数组

wave_data.shape = -1, 2

# -1代表左声道,2代表右声道

# 通过fromstring函数将字符串转换为数组,通过其参数dtype指定转换后的数据格式,由于我们的声音格式是以两个字节表示一个取样值,

# 因此采用short数据类型转换。现在我们得到的wave_data是一个一维的short类型的数组,但是因为我们的声音文件是双声道的,

# 因此它由左右两个声道的取样交替构成:LRLRLRLR....LR(L表示左声道的取样值,R表示右声道取样值)。修改wave_data的sharp之后:

# 将wave_data数组改为2列,行数自动匹配。在修改shape的属性时,需使得数组的总长度不变。v

wave_data = wave_data.T

# 将波形数据转换为数组

freq = [self.df*self.collect_point_num for n in range(0,self.collect_point_num)]

# 通过取样点数和取样频率计算出每个取样的时间

3.划分采样位置,建立频谱图坐标系,根据采样时间标记采样点在频谱图上的位置

wave_data2保存声音字节数组转置后的结果,为列数为1存储的数组

固定第一位,划分第二维区间从0一直扫描到行尾

避免波形字节数组过长,利用numpy.fft.fft对压缩为1/2的波形字节数组进行快速傅里叶变换,常规显示采样频率一半的频谱

设定如果每个取样点的取样时间大于4000ms,分隔单位为10的波形数组显示

def Data_collection(self):

wave_data = numpy.fromstring(self.str_data,dtype=numpy.short)

# 根据声道数和量化单位,将读取的二进制数据转换为一个可以计算的数组

wave_data.shape = -1.2

# -1代表左声道,2代表右声道

# 通过fromstring函数将字符串转换为数组,通过其参数dtype指定转换后的数据格式,由于我们的声音格式是以两个字节表示一个取样值,

# 因此采用short数据类型转换。现在我们得到的wave_data是一个一维的short类型的数组,但是因为我们的声音文件是双声道的,

# 因此它由左右两个声道的取样交替构成:LRLRLRLR....LR(L表示左声道的取样值,R表示右声道取样值)。修改wave_data的sharp之后:

# 将wave_data数组改为2列,行数自动匹配。在修改shape的属性时,需使得数组的总长度不变。v

wave_data = wave_data.T

# 将波形数据转换为数组

freq = [self.df*self.collect_point_num for n in range(0,self.collect_point_num)]

# 通过取样点数和取样频率计算出每个取样的时间

wave_data2 = wave_data[0][self.start:self.start+self.collect_point_num]

c = numpy.fft.fft(wave_data2)*2/self.collect_point_num

# 常规显示采样频率一半的频谱

d = int(len(c)/2)

while freq[0] > 4000:

d -= 10

pylab.plot(freq[:d-1],abs(c[:d-1]),"r")

pylab.show()

python console:频谱的时间段划分似乎造成了误差,导致统计结果趋于集中

fft.png

Test1:打印波形字节数组长度以及每个采样点采样花费的时间

def Data_collection(self):

wave_data = numpy.fromstring(self.str_data,dtype=numpy.short)

# 根据声道数和量化单位,将读取的二进制数据转换为一个可以计算的数组

wave_data.shape = -1, 2

# -1代表左声道,2代表右声道

# 通过fromstring函数将字符串转换为数组,通过其参数dtype指定转换后的数据格式,由于我们的声音格式是以两个字节表示一个取样值,

# 因此采用short数据类型转换。现在我们得到的wave_data是一个一维的short类型的数组,但是因为我们的声音文件是双声道的,

# 因此它由左右两个声道的取样交替构成:LRLRLRLR....LR(L表示左声道的取样值,R表示右声道取样值)。修改wave_data的sharp之后:

# 将wave_data数组改为2列,行数自动匹配。在修改shape的属性时,需使得数组的总长度不变。v

wave_data = wave_data.T

# 将波形数据转换为数组

freq = [self.df*self.collect_point_num for n in range(0,self.collect_point_num)]

print(freq)

# 通过取样点数和取样频率计算出每个取样的时间

wave_data2 = wave_data[0][self.start:self.start+self.collect_point_num]

c = numpy.fft.fft(wave_data2)*2/self.collect_point_num

d = int(len(c)/2)

print(d)

python console

print.jpg

Test2: 原来是设定的采样时间过小,修改统计条件为 freq[0] > 44101

def Data_collection(self):

wave_data = numpy.fromstring(self.str_data,dtype=numpy.short)

# 根据声道数和量化单位,将读取的二进制数据转换为一个可以计算的数组

wave_data.shape = -1, 2

# -1代表左声道,2代表右声道

# 通过fromstring函数将字符串转换为数组,通过其参数dtype指定转换后的数据格式,由于我们的声音格式是以两个字节表示一个取样值,

# 因此采用short数据类型转换。现在我们得到的wave_data是一个一维的short类型的数组,但是因为我们的声音文件是双声道的,

# 因此它由左右两个声道的取样交替构成:LRLRLRLR....LR(L表示左声道的取样值,R表示右声道取样值)。修改wave_data的sharp之后:

# 将wave_data数组改为2列,行数自动匹配。在修改shape的属性时,需使得数组的总长度不变。v

wave_data = wave_data.T

# 将波形数据转换为数组

freq = [self.df*self.collect_point_num for n in range(0,self.collect_point_num)]

print(freq)

# 通过取样点数和取样频率计算出每个取样的时间

wave_data2 = wave_data[0][self.start:self.start+self.collect_point_num]

c = numpy.fft.fft(wave_data2)*2/self.collect_point_num

d = int(len(c)/2)

print(d)

while freq[0] > 44101:

d -= 0.1

pylab.plot(freq[:d-1],abs(c[:d-1]),"r")

pylab.show()

python console采样的分布过于密集,不适合用频谱图进行统计

pinpu.png

Test3:使用波形图,分别用subplot211与subplot212标识左右声道的波形

import wave

import pyaudio

import numpy

from matplotlib import pylab

#打开wav文档,文件路径根据需要修改

wf = wave.open("F:\\work\\war.wav","rb")

#创建PyAudio对象

p = pyaudio.PyAudio()

class Audio(object):

def __init__(self):

self.channels = wf.getnchannels()

# 返回音频通道数

self.rate = wf.getframerate()

# 返回采样频率。

self.format = p.get_format_from_width(wf.getsampwidth())

# 返回指定宽度的PortAudio格式常量。

self.stream = p.open(format=self.format,channels=self.channels,rate=self.rate,output=True)

# 使用所需的音频参数在所需设备上打开一个流

self.nframes = wf.getnframes()

# 返回音频帧数

self.collect_point_num = 44100

# 采样点数,修改采样点数和起始位置进行不同位置和长度的音频波形分析

self.start = 0

# 开始采样位置

def read_data(self):

self.str_data = wf.readframes(self.nframes)

# 读取声音数据,传递一个参数指定需要读取的长度(以取样点为单位),readframes返回的是二进制数据(即bytes数组)

# print(self.str_data)

wf.close()

def convert_data(self):

self.df = self.rate / (self.collect_point_num - 1)

# print(self.df)

# 使用全局采样频率除以全局采样点数,以求出帧率

def Data_collection(self):

wave_data = numpy.fromstring(self.str_data,dtype=numpy.short)

# 根据声道数和量化单位,将读取的二进制数据转换为一个可以计算的数组

wave_data.shape = -1, 2

# -1代表左声道,2代表右声道

# 通过fromstring函数将字符串转换为数组,通过其参数dtype指定转换后的数据格式,由于我们的声音格式是以两个字节表示一个取样值,

# 因此采用short数据类型转换。现在我们得到的wave_data是一个一维的short类型的数组,但是因为我们的声音文件是双声道的,

# 因此它由左右两个声道的取样交替构成:LRLRLRLR....LR(L表示左声道的取样值,R表示右声道取样值)。修改wave_data的sharp之后:

# 将wave_data数组改为2列,行数自动匹配。在修改shape的属性时,需使得数组的总长度不变。v

wave_data = wave_data.T

# 将波形数据转换为数组

freq = [self.df*self.collect_point_num for n in range(0,self.collect_point_num)]

# print(freq)

# 通过取样点数和取样频率计算出每个取样的时间

wave_data2 = wave_data[0][self.start:self.start+self.collect_point_num]

c = numpy.fft.fft(wave_data2)*2/self.collect_point_num

d = int(len(c)/2)

# print(d)

while freq[0] > 44101:

d -= 20

pylab.plot(freq[:d-1],c[:d-1],"r")

pylab.show()

def wavread(self):

wavfile = wf

params = wavfile.getparams()

framesra, frameswav = params[2], params[3]

datawav = wavfile.readframes(frameswav)

wavfile.close()

datause = numpy.fromstring(datawav, dtype=numpy.short)

datause.shape = -1, 2

datause = datause.T

time = numpy.arange(0, frameswav) * (1.0 / framesra)

return datause, time

def work(self):

self.read_data()

self.convert_data()

self.Data_collection()

if __name__ == '__main__':

aduio = Audio()

# aduio.work()

wavdata, wavtime = aduio.wavread()

pylab.title("Night.wav's Frames")

pylab.subplot(211)

pylab.plot(wavtime, wavdata[0], color='green')

pylab.subplot(212)

pylab.plot(wavtime, wavdata[1])

pylab.show()

python console

wave.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值