python---声压级计算

该博客介绍了如何使用Python计算声压级和响度,包括spl_en函数用于计算声压级,iso226函数用于计算响度。通过示例代码展示了如何对语音信号进行分帧处理并计算SPL,以及如何根据ISO标准绘制响度曲线。同时,指出了在使用plt.xlim()设置x轴范围时可能出现的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

声压级计算代码如下:

# 在spl.py文件里面的计算声压和响度函数
import numpy as np
import math
#np.seterr(divide='ignore', invalid='ignore')
def spl_en(x,fs,flen):
    '''
    :param x:代表输入的语音信号
    :param fs: 采样率
    :param flen: 一帧信号的时间长度,单位是毫秒
    :return: 声压级的值
    '''
    length = len(x)  # 得到输入语音的长度
    #每一帧信号的离散的点数
    m = int(flen * fs/1000)
    if length != m:
        print('length',length)
        print('m',m)
        print('输入信号长度与所定义帧长不等!')

    # 计算声压级根据定义计算有效声压,pa = sqrt((x(1)^2+x(2)^2+...+x(M)^2)/M)
    # 单位是Pa

    pp = 0
    for i in range(0,m-1):
        pp += x[i] ** 2

    pa = np.sqrt(pp / m)

    # 计算声压级,声压级值spl=20*log10(pa/p0),单位为dB
    #基准声压p0,单位为Pa
    p0 = 2 * 1e-5
    spl_value = 20*np.log10(pa / p0)

    return spl_value


# 计算响度函数
def iso226(phon):
    f = np.array([20 ,25, 31.5, 40, 50, 63, 80, 100, 125, 160, 200, 250, 315, 400, 500, 630, 800,
         1000 ,1250 ,1600, 2000, 2500, 3150, 4000, 5000, 6300, 8000, 10000, 12500])

    af = np.array([0.532, 0.506, 0.480, 0.455, 0.432 ,0.409 ,0.387 ,0.367, 0.349, 0.330, 0.315,
          0.301, 0.288, 0.276, 0.267, 0.259, 0.253, 0.250, 0.246, 0.244, 0.243, 0.243,
          0.243, 0.242, 0.242, 0.245, 0.254, 0.271, 0.301])

    Lu =np.array([-31.6 ,- 27.2, - 23.0, - 19.1 ,- 15.9, - 13.0 ,- 10.3 ,- 8.1 ,- 6.2 ,- 4.5, - 3.1,
          - 2.0 ,- 1.1, - 0.4,   0.0 ,  0.3 ,  0.5 ,  0.0 ,- 2.7, - 4.1 ,- 1.0,  1.7,
          2.5 ,  1.2 ,- 2.1 ,- 7.1 ,- 11.2, - 10.7 ,- 3.1])

    Tf = np.array([78.5 , 68.7 , 59.5 , 51.1 , 44.0 , 37.5 , 31.5,  26.5 , 22.1 , 17.9,  14.4,
          11.4 ,  8.6 ,  6.2 ,  4.4,   3.0,   2.2 ,  2.4 ,  3.5 ,  1.7 ,- 1.3 ,- 4.2,
          - 6.0, - 5.4, - 1.5,   6.0 , 12.6 , 13.9,  12.3])

    # 错误处理

    if ((phon < 0) or (phon > 90)):
        print('因素值超出了范围!')
        spl=0
        freq=0
    else:
        Ln = phon
        #从响度级计算声压级
        Af = 4.47 * math.e -3 * (10*(0.025*Ln) - 1.15) + (0.4*10*(((Tf+Lu)/10)-9 ))*af
        Lp = ((10 / af)* np.log10(np.abs(Af))) - Lu + 94  # 取对数这里是不能出现复数的,所以要加绝对值

        spl = Lp
        freq = f

    return [spl,freq]




其他调用函数:

#在spl_jisuan.py文件里面
from spl import spl_en
import numpy as np
from matplotlib import  pyplot as plt
import librosa


data,fs = librosa.load('C2_2_y.wav',sr=None)

length = len(data)

# % 每帧大小为M,当语音长度不是帧长的整数倍时:
# % (1)若剩余长度大于等于帧长的二分之一,则补零至帧长
# % (2)若剩余长度小于帧长的二分之一,则舍弃

framlen = 100
#每帧信号的离散点数
M = int(fs * framlen/1000)   # 一帧有多少点数
m = np.mod(length,M)  # 求余数
if m >= M//2:  #补零
    x = np.pad(data,M-m,mode='constant',constant_values=0)
    length = len(x)

else:
    l = np.floor(length//M)  # 下取整函数,要舍弃
    x = data[0:M*l]  # 选择M*l个点数,刚好把多余的部分截断了
    length = len(x)

N = length // M  #最终的分帧数

s = np.zeros((1,M))  # 一帧存储M个点数
spl_f = np.zeros((1,int(N)))  # 分帧数
for i in range(1,int(N)):
    s = x[(i-1)*M:i*M]  # 一次一帧个点数
    spl_f[0,i] = spl_en(s,fs,framlen)  #算spl,存放到数组里面,每一帧算出一个标量

t = np.arange(0,length)   # 语句的长度,选取时间的长度
SPL = np.zeros((1,length))
for r in range(1,int(N)):  # 把结果存放到对应的SPL数组里面
    SPL[0,(r-1)*M:r*M]=spl_f[0,r]

plt.figure()
plt.subplot(2,1,1)
plt.plot(t/fs,x)  # 算出时间是多少秒,对应的是x的语句的长度,这个是截断以后的长度
plt.xlabel('time/s')
plt.ylabel('wave spec')
plt.subplot(2,1,2)
plt.step(t/fs,SPL[0],'r')  # 时间,算出来的SPL
plt.xlabel('time/s')
plt.ylabel('db')
plt.title('yuyin xinhao de shengyaji db')
plt.show()
#在com_iso.py文件里面
from spl import spl_en,iso226
import numpy as np
from matplotlib import  pyplot as plt
import librosa

phon=50
spl = iso226(phon)
plt.figure()  # 使用plt.subplots()的时候,不需要添加plt.figure()也是可以的,
# 或者fig=plt.figure()
# ax=fig.add_subplots(121)
plt.semilogx(spl[1],spl[0],':','color','k')
# plt.xlim(20,20000)
# plt.ylim(-10,130)
# plt.axis([20,20000,-10,130])
y_ticks = range(-10,200,10)
plt.yticks(y_ticks,y_ticks,rotation=60)
plt.xlabel('freq/hz')
plt.ylabel('shengya  jibie  db')
plt.title('phone=50')
#plt.yticks(np.arange(start=-10,stop=130,step=10),np.arange(start=-10,stop=130,step=10),rotation=60)
plt.grid(b=True,linestyle='--',linewidth=0.5)  # 是否显示网格线
plt.box()  # 添加边框,还有其他的用法也是可以用的。plt.gca()创建这个对象,再条用spine的一系列属性设置值。
plt.show()

结果是:

 

 显示第二张图的时候,是不能用plt.xlim()函数设置x轴的范围的,我也不太明白为什么,如果设置了,还是现在这样子的,但是半对数曲线就显示不出来了,可能是因为范围的问题吧。

用到的参考资料为:

Matplotlib绘图(一)-边框线及坐标轴的设置_帅兄心安否的博客-CSDN博客_matplotlib 边框https://blog.csdn.net/weixin_44560088/article/details/107165510matplotlib之pyplot模块——显示/关闭子图边框(轴脊)(box())_mighty13的博客-CSDN博客_matplotlib 子图边框https://blog.csdn.net/mighty13/article/details/116571742声压与声压级的计算_jianghuzhijian的博客-CSDN博客_声压级计算https://blog.csdn.net/jianghuzhijian/article/details/103798289

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值