89 行
2.5 KiB
Python
89 行
2.5 KiB
Python
import numpy as np
|
|
from scipy.fft import fft
|
|
import soundfile as sf
|
|
from numpy import log10
|
|
import math
|
|
|
|
# Average Noise Spectral Level
|
|
def ANSL(u, fs, M, A=0, N=None, D=None, w=None):
|
|
"""
|
|
:param u: Voltage data (Unit: V)
|
|
:param fs: Sampling rate (Unit: Hz)
|
|
:param M: Sensitivity (Unit: dBV re 1uPa)
|
|
:param A: Preamplifier (Unit: dB)
|
|
:param N: Segment length
|
|
:param D: Overlap length
|
|
:param w: Window
|
|
:return: Spectral level
|
|
"""
|
|
L = len(u)
|
|
if N == None:
|
|
if L >= fs:
|
|
N = round(fs)
|
|
else:
|
|
N = L
|
|
elif N > L:
|
|
raise Exception("Segment length is larger than data length.")
|
|
|
|
if D == None:
|
|
D = 0
|
|
|
|
if w is None:
|
|
w = np.hamming(N)
|
|
G = np.mean(np.square(abs(w)))
|
|
|
|
K = 1 + math.floor((L-N) / (N-D))
|
|
|
|
T = N / fs
|
|
df = 1 / T
|
|
X2 = np.zeros(N)
|
|
for k in range(K):
|
|
X = fft(w * u[round(k*(N-D)):round(k*(N-D)+N)])
|
|
X2 += np.square(abs(X))
|
|
|
|
spl = 10 * log10(X2) - 10 * log10(N*fs*G*K/2) - M - A
|
|
freq = np.arange(0, fs/2, df)
|
|
spl = spl[0:len(freq)]
|
|
|
|
return freq, spl
|
|
|
|
|
|
# 1/3 Octave Spectral Level
|
|
def OneThirdOct_SPL(freq, spl, f_start, Npoints):
|
|
"""
|
|
:param freq: Frequency
|
|
:param spl: 1 Hz bandwidth spectral level
|
|
:param f_start: Starting frequency of the 1/3 octave
|
|
:param Npoints: The number of frequency points
|
|
:return: 1/3 Octave Spectral Level
|
|
"""
|
|
fC = f_start * np.power(2, np.arange(Npoints)/3)
|
|
fL = f_start * np.power(2, np.arange(Npoints)/3 - 1.0/6)
|
|
fH = f_start * np.power(2, np.arange(Npoints)/3 + 1.0/6)
|
|
|
|
spl_oct = np.zeros(Npoints)
|
|
for it in range(Npoints):
|
|
# idx = (freq >= fL[it]) & (freq <= fH[it])
|
|
idx = np.where((freq >= fL[it]) & (freq <= fH[it]))
|
|
# print(idx)
|
|
# print(spl[idx])
|
|
spl_oct[it] = 10 * log10(np.mean(np.power(10, spl[idx]/10)))
|
|
# print(spl_oct[it])
|
|
|
|
return fC, spl_oct
|
|
|
|
def call_oanp(soundFile, M, A=0):
|
|
[x, fs] = sf.read(soundFile)
|
|
u = 3 * x # Voltage data
|
|
# M = -164.0 # Sensitivity
|
|
# A = 0 # Preamplifier
|
|
N = fs # Segment length
|
|
D = N/2 # Overlap length
|
|
w = np.hanning(N) # Window
|
|
|
|
# Average Noise Spectral Level
|
|
[freq, spl] = ANSL(u, fs, M, A, N, D, w)
|
|
# 1/3 Octave Spectral Level
|
|
[fC, spl_oct] = OneThirdOct_SPL(freq, spl, f_start=20, Npoints=28)
|
|
|
|
return [freq, spl, fC, spl_oct] |