178 lines
5.8 KiB
Python
178 lines
5.8 KiB
Python
import numpy as np
|
|
|
|
|
|
'''
|
|
Constants
|
|
'''
|
|
# 1) Parameters of Short Time Fourier Analysis:
|
|
Fs_ref = 8e3 # 1.1) Reference Sampling frequency
|
|
M_ref = 512 # 1.2) Size of analysis window
|
|
#Mo_ref = 0.75*M_ref # 1.3) Number of overlapping samples in consecutive frames
|
|
Mo_ref = 352
|
|
|
|
# 2) Parameters of Noise Spectrum Estimate
|
|
w = 1 # 2.1) Size of frequency smoothing window function = 2*w+1
|
|
alpha_s_ref = 0.9 # 2.2) Recursive averaging parameter for the smoothing operation
|
|
Nwin = 8 # 2.3) Resolution of local minima search
|
|
Vwin = 15
|
|
delta_s = 1.67 # 2.4) Local minimum factor
|
|
Bmin = 1.66
|
|
delta_y = 4.6 # 2.4) Local minimum factor
|
|
delta_yt = 3
|
|
alpha_d_ref = 0.85 # 2.7) Recursive averaging parameter for the noise
|
|
|
|
# 3) Parameters of a Priori Probability for Signal-Absence Estimate
|
|
alpha_xi_ref = 0.7 # 3.1) Recursive averaging parameter
|
|
|
|
# 4) Parameters of "Decision-Directed" a Priori SNR Estimate
|
|
alpha_eta_ref = 0.95 # 4.1) Recursive averaging parameter
|
|
eta_min_dB = -18 # 4.2) Lower limit constraint
|
|
|
|
# 5) Flags
|
|
nonstat = 'medium' #Non stationarity # new version
|
|
|
|
Fs = Fs_ref
|
|
M = int(M_ref)
|
|
Mo = int(Mo_ref)
|
|
Mno = int(M-Mo)
|
|
alpha_s = alpha_s_ref
|
|
alpha_d = alpha_d_ref
|
|
alpha_eta = alpha_eta_ref
|
|
alpha_xi = alpha_xi_ref
|
|
|
|
alpha_d_long = 0.99
|
|
eta_min = 10**(eta_min_dB/10)
|
|
|
|
#b = hanning(2*w+1)
|
|
#b = b/sum(b) # normalize the window function
|
|
b = np.array([0, 1, 0])
|
|
|
|
M21 = int(M/2+1)
|
|
|
|
class NoiseEstimator(object):
|
|
def update(self, features):
|
|
pass
|
|
|
|
class ImcraNoiseEstimator(NoiseEstimator):
|
|
def __init__(self):
|
|
self.l = 0 #count of frame
|
|
self.l_mod_lswitch = 0
|
|
self.S = np.zeros(M21)
|
|
self.St = np.zeros(M21)
|
|
self.Sy = np.zeros(M21)
|
|
self.Smin = np.zeros(M21)
|
|
self.Smint = np.zeros(M21)
|
|
self.SMact = np.zeros(M21)
|
|
self.SMactt = np.zeros(M21)
|
|
self.SW = np.zeros((M21,Nwin))
|
|
self.SWt = np.zeros((M21,Nwin))
|
|
self.lambda_d = np.zeros(M21)
|
|
self.lambda_dav = np.zeros(M21)
|
|
|
|
def update(self, features):
|
|
Ya2 = features['signal_power']
|
|
self.eta_2term = features['eta_2term']
|
|
|
|
self.l = self.l + 1
|
|
gamma = Ya2 / np.maximum(self.lambda_d, 1e-10) #post_snr
|
|
eta = alpha_eta*self.eta_2term + (1-alpha_eta)*np.maximum(gamma-1,0) #prior_snr
|
|
eta = np.maximum(eta,eta_min)
|
|
v = gamma*eta/(1+eta)
|
|
|
|
# 2.1. smooth over frequency
|
|
Sf = np.convolve(b, Ya2) # smooth over frequency
|
|
Sf = Sf[w:M21+w]
|
|
# if l==1
|
|
if self.l == 1 :
|
|
self.Sy = Ya2
|
|
self.S = Sf
|
|
self.St = Sf
|
|
self.lambda_dav = Ya2
|
|
else :
|
|
self.S = alpha_s * self.S + (1-alpha_s) * Sf # smooth over time
|
|
|
|
if self.l < 15 :
|
|
self.Smin = self.S
|
|
self.SMact = self.S
|
|
else :
|
|
self.Smin = np.minimum(self.Smin, self.S)
|
|
self.SMact = np.minimum(self.SMact, self.S)
|
|
|
|
# Local Minima Search
|
|
I_f = np.zeros(M21)
|
|
for i in range(M21) :
|
|
I_f[i] = Ya2[i]<delta_y*Bmin*self.Smin[i] and self.S[i]<delta_s*Bmin*self.Smin[i] and 1
|
|
conv_I = np.convolve(b, I_f)
|
|
conv_I = conv_I[w:M21+w]
|
|
Sft = self.St
|
|
idx = [i for i, v in enumerate(conv_I) if v>0]
|
|
if len(idx)!=0 :
|
|
if w :
|
|
conv_Y = np.convolve(b, I_f*Ya2)
|
|
conv_Y = conv_Y[w:M21+w]
|
|
Sft[idx] = conv_Y[idx]/conv_I[idx]
|
|
else :
|
|
Sft[idx] = Ya2[idx]
|
|
|
|
if self.l < 15 :
|
|
self.St = self.S
|
|
self.Smint = self.St
|
|
self.SMactt = self.St
|
|
else :
|
|
self.St[:] = alpha_s * self.St + (1-alpha_s) * Sft
|
|
self.Smint[:] = np.minimum(self.Smint, self.St)
|
|
self.SMactt[:] = np.minimum(self.SMactt, self.St)
|
|
|
|
qhat = np.ones(M21)
|
|
phat = np.zeros(M21)
|
|
|
|
if nonstat == 'low' :
|
|
gamma_mint = Ya2/Bmin/np.maximum(self.Smin,1e-10)
|
|
zetat = self.S/Bmin/np.maximum(self.Smin,1e-10)
|
|
else :
|
|
gamma_mint = Ya2/Bmin/np.maximum(self.Smint,1e-10)
|
|
zetat = self.S/Bmin/np.maximum(self.Smint,1e-10)
|
|
|
|
for idx in range(M21) :
|
|
if gamma_mint[idx]>1 and gamma_mint[idx]<delta_yt and zetat[idx]<delta_s :
|
|
qhat[idx] = (delta_yt-gamma_mint[idx])/(delta_yt-1)
|
|
phat[idx] = 1/(1+qhat[idx]/(1-qhat[idx])*(1+eta[idx])*np.exp(-v[idx]))
|
|
if gamma_mint[idx]>delta_yt or zetat[idx]>=delta_s :
|
|
phat[idx] = 1
|
|
|
|
self.l_mod_lswitch = self.l_mod_lswitch + 1
|
|
if self.l_mod_lswitch == Vwin :
|
|
self.l_mod_lswitch = 0
|
|
|
|
if self.l == Vwin :
|
|
for i in range(Nwin):
|
|
self.SW[:,i] = self.S
|
|
self.SWt[:, i] = self.St
|
|
else :
|
|
self.SW[:,:Nwin-1] = self.SW[:,1:Nwin]
|
|
self.SW[:,Nwin-1] = self.SMact
|
|
self.Smin = self.SW.min(1)
|
|
self.SMact = self.S
|
|
self.SWt[:,:Nwin-1] = self.SWt[:,1:Nwin]
|
|
self.SWt[:,Nwin-1] = self.SMactt
|
|
self.Smint = self.SWt.min(1)
|
|
self.SMactt = self.St
|
|
|
|
alpha_dt = alpha_d + (1-alpha_d)*phat
|
|
self.lambda_dav = alpha_dt * self.lambda_dav + (1-alpha_dt)*Ya2
|
|
if self.l < 15 :
|
|
self.lambda_dav_long = self.lambda_dav
|
|
else :
|
|
alpha_dt_long = alpha_d_long + (1-alpha_d_long)*phat
|
|
self.lambda_dav_long = alpha_dt_long * self.lambda_dav_long + (1-alpha_dt_long)*Ya2
|
|
|
|
# 2.4. Noise Spectrum Estimate
|
|
if nonstat == 'high' :
|
|
self.lambda_d = 2 * self.lambda_dav
|
|
else :
|
|
self.lambda_d = 1.4685 * self.lambda_dav
|
|
|
|
return self.lambda_d
|
|
|
|
|