import numpy as np
from brian2 import ms, kHz
from .filterbank import (ControlFilterbank, CombinedFilterbank,
RestructureFilterbank)
from .filterbanklibrary import *
__all__ = ['DCGC']
def set_parameters(cf,param):
parameters=dict()
parameters['b1'] = 1.81
parameters['c1'] = -2.96
parameters['b2'] = 2.17
parameters['c2'] = 2.2
parameters['decay_tcst'] = .5*ms
parameters['lev_weight'] = .5
parameters['level_ref'] = 50.
parameters['level_pwr1'] = 1.5
parameters['level_pwr2'] = .5
parameters['RMStoSPL'] = 30.
parameters['frat0'] = .2330
parameters['frat1'] = .005
parameters['lct_ERB'] = 1.5 #value of the shift in ERB frequencies
parameters['frat_control'] = 1.08
parameters['order_gc']=4
parameters['ERBrate']= 21.4*np.log10(4.37*(cf/kHz)+1)
parameters['ERBwidth']= 24.7*(4.37*(cf/kHz)+1)
if param:
if not isinstance(param, dict):
raise TypeError('given parameters must be a dict')
for key in param.keys():
if not key in parameters:
raise Exception(key + ' is invalid key entry for given parameters')
parameters[key] = param[key]
return parameters
#defition of the controler class
class AsymCompUpdate:
def __init__(self,target,samplerate,fp1,param):
fp1=np.atleast_1d(fp1)
self.iteration=0
self.target=target
self.samplerate=samplerate
self.fp1=fp1
self.exp_deca_val = np.exp(-1/(param['decay_tcst'] *samplerate)*np.log(2))
self.level_min = 10**(- param['RMStoSPL']/20)
self.level_ref = 10**(( param['level_ref'] - param['RMStoSPL'])/20)
self.b=param['b2']
self.c=param['c2']
self.lev_weight=param['lev_weight']
self.level_ref=param['level_ref']
self.level_pwr1=param['level_pwr1']
self.level_pwr2=param['level_pwr2']
self.RMStoSPL=param['RMStoSPL']
self.frat0=param['frat0']
self.frat1=param['frat1']
self.level1_prev=-100
self.level2_prev=-100
self.p0=2
self.p1=1.7818*(1-0.0791*self.b)*(1-0.1655*abs(self.c))
self.p2=0.5689*(1-0.1620*self.b)*(1-0.0857*abs(self.c))
self.p3=0.2523*(1-0.0244*self.b)*(1+0.0574*abs(self.c))
self.p4=1.0724
def __call__(self,*input):
value1=input[0][-1,:]
value2=input[1][-1,:]
level1 = np.maximum(np.maximum(value1,0),self.level1_prev*self.exp_deca_val)
level2 = np.maximum(np.maximum(value2,0),self.level2_prev*self.exp_deca_val)
self.level1_prev=level1
self.level2_prev=level2
level_total=self.lev_weight*self.level_ref*(level1/self.level_ref)**self.level_pwr1+(1-self.lev_weight)*self.level_ref*(level2/self.level_ref)**self.level_pwr2
level_dB=20*np.log10(np.maximum(level_total,self.level_min))+self.RMStoSPL
frat = self.frat0 + self.frat1*level_dB
fr2 = self.fp1*frat
self.iteration+=1
self.target.filt_b, self.target.filt_a=asymmetric_compensation_coeffs(self.samplerate,fr2,self.target.filt_b,self.target.filt_a,self.b,self.c,self.p0,self.p1,self.p2,self.p3,self.p4)
[docs]class DCGC(CombinedFilterbank):
'''
The compressive gammachirp auditory filter as described in Irino, T. and
Patterson R., "A compressive gammachirp auditory filter for both
physiological and psychophysical data", JASA 2001.
Technical implementation details and notation can be found in Irino, T. and
Patterson R., "A Dynamic Compressive Gammachirp Auditory Filterbank",
IEEE Trans Audio Speech Lang Processing.
The model consists of a control pathway and a signal pathway in parallel.
The control pathway consists of a bank of bandpass filters followed by a
bank of highpass filters (this chain yields a bank of gammachirp filters).
The signal pathway consist of a bank of fix bandpass filters followed by a
bank of highpass filters with variable cutoff frequencies (this chain
yields a bank of gammachirp filters with a level-dependent bandwidth). The
highpass filters of the signal pathway are controlled
by the output levels of the two stages of the control pathway.
Initialised with arguments:
``source``
Source of the cochlear model.
``cf``
List or array of center frequencies.
``update_interval``
Interval in samples controlling how often the band pass filter of the
signal pathway is updated. Smaller values are more accurate, but give
longer computation times.
``param``
Dictionary used to overwrite the default parameters given in the
original paper.
The possible parameters to change and their default values (see Irino, T.
and Patterson R., "A Dynamic Compressive Gammachirp
Auditory Filterbank", IEEE Trans Audio Speech Lang Processing) are::
param['b1'] = 1.81
param['c1'] = -2.96
param['b2'] = 2.17
param['c2'] = 2.2
param['decay_tcst'] = .5*ms
param['lev_weight'] = .5
param['level_ref'] = 50.
param['level_pwr1'] = 1.5
param['level_pwr2'] = .5
param['RMStoSPL'] = 30.
param['frat0'] = .2330
param['frat1'] = .005
param['lct_ERB'] = 1.5 #value of the shift in ERB frequencies
param['frat_control'] = 1.08
param['order_gc']=4
param['ERBrate']= 21.4*log10(4.37*cf/1000+1) # cf is the center frequency
param['ERBwidth']= 24.7*(4.37*cf/1000 + 1)
'''
def __init__(self, source,cf,update_interval=1,param={}):
CombinedFilterbank.__init__(self, source)
source = self.get_modified_source()
parameters=set_parameters(cf,param)
ERBspace = np.mean(np.diff(parameters['ERBrate']))
cf = np.asarray(np.atleast_1d(cf))
#bank of passive gammachirp filters. As the control path uses the same passive filterbank than the signal path (buth shifted in frequency)
#this filterbanl is used by both pathway.
pGc=LogGammachirp(source,cf,b=parameters['b1'], c=parameters['c1'])
# self.gc.filt_b=pGc.filt_b
# self.gc.filt_a=pGc.filt_a
fp1 = cf + parameters['c1']*parameters['ERBwidth']*parameters['b1']/parameters['order_gc']
nbr_cf=len(cf)
#### Control Path ####
n_ch_shift = round(parameters['lct_ERB']/ERBspace); #value of the shift in channels
indch1_control = np.minimum(np.maximum(1, np.arange(1,nbr_cf+1)+n_ch_shift),nbr_cf).astype(int)-1
fp1_control = fp1[indch1_control]
pGc_control=RestructureFilterbank(pGc,indexmapping=indch1_control)
fr2_control = parameters['frat_control']*fp1_control
asym_comp_control=AsymmetricCompensation(pGc_control, fr2_control,b=parameters['b2'], c=parameters['c2'])
#### Signal Path ####
fr1=fp1*parameters['frat0']
signal_path= AsymmetricCompensation(pGc, fr1,b=parameters['b2'], c=parameters['c2'])
# self.asym_comp.filt_b=signal_path.filt_b
# self.asym_comp.filt_a=signal_path.filt_a
#### Controler ####
updater = AsymCompUpdate(signal_path,source.samplerate,fp1,parameters) #the updater
control = ControlFilterbank(signal_path, [pGc_control,asym_comp_control], signal_path, updater, update_interval)
self.set_output(control)