@@ -12,11 +12,13 @@ class Cochlea(FilterBank):
12
12
'''
13
13
Model of Cochlea (a subclass of FilterBank)
14
14
'''
15
- def __init__ (self , types = None , species = None , CF0 = 20 , length = 20 , l_factor = 3.8 , xs = None , cfs = None , rho = 1.000 , Ap = None , bp = None , Bu = None , gain_const = None , peak_magndb = None , Bpeak = None , fpeak = None , phiaccum = None , Nbeta = None , Nf = None , Qerb = None , ERBbeta = None , ERBf = None , Qn = None , Qn2 = None , BWndBbeta = None , BWndBf = None , BWn2dBbeta = None , BWn2dBf = None , Sbeta = None , Sf = None , n = 10 , n2 = 3 , betas = None , freqs = None ):
15
+ def __init__ (self , species = None , type = None , CF0 = 20 , l_factor = 3.8 , length = 20 , xs = None , cfs = None , rho = 1.000 , Ap = None , bp = None , Bu = None , gain_const = None , peak_magndb = None , Bpeak = None , fpeak = None , phiaccum = None , Nbeta = None , Nf = None , Qerb = None , ERBbeta = None , ERBf = None , Qn = None , Qn2 = None , BWndBbeta = None , BWndBf = None , BWn2dBbeta = None , BWn2dBf = None , Sbeta = None , Sf = None , n = 10 , n2 = 3 , betas = None , freqs = None ):
16
16
'''
17
- Initializes Cochlea. Most arguments are the same as for `FilterBank` object
17
+ Initializes Cochlea. Most arguments are the same as for `FilterBank` object.
18
18
19
19
Attributes:
20
+ species: fast way to initialize Cochlea for certain species
21
+ num_filters: number of filters to model cochlea with. Default is 4.
20
22
CF0: characteristic frequency (kHz) of base of cochlea
21
23
length: length of cochlea (mm)
22
24
l_factor: constant factor for cochlear model (mm)
@@ -28,30 +30,40 @@ def __init__(self, types=None, species=None, CF0=20, length=20, l_factor=3.8, xs
28
30
'''
29
31
if species is not None :
30
32
CF0 , l_factor , length = self ._given_species (species )
31
-
32
33
self .cochlea_length = length
34
+ self .cf = (lambda x : CF0 * np .exp (- x / l_factor ))
33
35
34
- args = {'Ap' :Ap , 'bp' :bp , 'Bu' :Bu , 'gain_const' :gain_const , 'peak_magndb' :peak_magndb ,
35
- 'Bpeak' :Bpeak , 'fpeak' :fpeak , 'phiaccum' :phiaccum , 'Nbeta' :Nbeta , 'Nf' :Nf , 'Qerb' :Qerb , 'ERBbeta' :ERBbeta , 'ERBf' :ERBf , 'Qn' :Qn , 'Qn2' :Qn2 , 'BWndBbeta' :BWndBbeta , 'BWndBbeta' :BWndBf , 'BWn2dBbeta' :BWn2dBbeta , 'BWn2dBf' :BWn2dBf , 'Sbeta' :Sbeta , 'Sf' :Sf , 'n' :n , 'n2' :n2 , 'betas' :betas , 'freqs' :freqs }
36
- num_filters = 1
37
- for v in args .values ():
38
- if np .ndim (v ) >= 1 :
39
- num_filters = max (num_filters , len (v ))
36
+ type = 'P' if type is None else type
40
37
41
- self .cf = (lambda x : CF0 * np .exp (- x / l_factor ))
42
- if cfs is None :
43
- if xs is None :
44
- xs = np .linspace (0 , length , num_filters )
45
- cfs = [self .cf (x ) for x in xs ]
38
+ if species is not None :
39
+ xs = np .linspace (0 , length , 4 ) # let user set?
40
+ cfs = self .cf (xs )
41
+ Ap = 0.3768 * np .exp (- 0.1366 * cfs ) # seems improbable
42
+ bp = [1. , 1. , 1. , 1. ]
43
+ Bu = 3.714 * np .exp (0.03123 * cfs ) # same here
44
+ args = {'Ap' :Ap , 'bp' :bp , 'Bu' :Bu , 'cf' :cfs }
46
45
else :
47
- if xs is not None :
48
- raise Exception ('Please provide either only a list of all locations along cochlea or a list of all characteristic frequencies' )
49
- xs = [- np .log (c / CF0 )* l_factor for c in cfs ]
50
- self .xs = xs
51
- types = 'P' if types is None else types
46
+ args = {'Ap' :Ap , 'bp' :bp , 'Bu' :Bu , 'gain_const' :gain_const , 'peak_magndb' :peak_magndb ,
47
+ 'Bpeak' :Bpeak , 'fpeak' :fpeak , 'phiaccum' :phiaccum , 'Nbeta' :Nbeta , 'Nf' :Nf , 'Qerb' :Qerb , 'ERBbeta' :ERBbeta , 'ERBf' :ERBf , 'Qn' :Qn , 'Qn2' :Qn2 , 'BWndBbeta' :BWndBbeta , 'BWndBbeta' :BWndBf , 'BWn2dBbeta' :BWn2dBbeta , 'BWn2dBf' :BWn2dBf , 'Sbeta' :Sbeta , 'Sf' :Sf , 'n' :n , 'n2' :n2 }
48
+ num_filters = 1
49
+ for v in args .values ():
50
+ if np .ndim (v ) >= 1 :
51
+ num_filters = max (num_filters , len (v ))
52
52
53
- args ['cf' ] = cfs
54
- super ().__init__ (topology = 'parallel' , type = types , ** args )
53
+ if cfs is None :
54
+ if xs is None :
55
+ xs = np .linspace (0 , length , num_filters )
56
+ cfs = [self .cf (x ) for x in xs ]
57
+ else :
58
+ if xs is not None :
59
+ raise Exception ('Please provide either only a list of all locations along cochlea or a list of all characteristic frequencies' )
60
+ xs = [- np .log (cf / CF0 )* l_factor for cf in cfs ]
61
+
62
+ self .xs = xs
63
+ args ['cf' ] = cfs
64
+ args ['betas' ] = [betas for _ in range (num_filters )]
65
+ args ['freqs' ] = [freqs for _ in range (num_filters )]
66
+ super ().__init__ (topology = 'series' , type = type , ** args )
55
67
56
68
apexmost_filter = self .filters [- 1 ]
57
69
@@ -64,8 +76,6 @@ def __init__(self, types=None, species=None, CF0=20, length=20, l_factor=3.8, xs
64
76
self .bp_fun = (lambda x : np .exp (np .interp (x , self .xs , np .log (np .array (bp )))))
65
77
self .Bu_fun = (lambda x : np .exp (np .interp (x , self .xs , np .log (np .array (Bu )))))
66
78
67
- # beta = w/2pi/CF(x)
68
-
69
79
p = 1j * bp_apex - Ap_apex
70
80
# k and Z both normalized to not depend on l
71
81
self .wavenumber = (lambda beta : (beta / l_factor ) * 2 * Bu_apex * (1j * beta + Ap_apex ) / ((1j * beta - p )* (1j * beta - p .conjugate ())))
@@ -76,18 +86,16 @@ def __init__(self, types=None, species=None, CF0=20, length=20, l_factor=3.8, xs
76
86
self .Z = self .impedance
77
87
78
88
@classmethod
79
- def five_param (cls , types = None , aAp = None , bAp = None , bp = None , aBu = None , bBu = None , gain_const = None , peak_magndb = None , CF0 = 20 , length = 20 , xs = None , rho = 1.000 ):
89
+ def five_param (cls , type = None , aAp = None , bAp = None , bp = None , aBu = None , bBu = None , gain_const = None , peak_magndb = None , CF0 = 20 , l_factor = 3.8 , length = 20 , xs = None , rho = 1.000 , betas = None , freqs = None ):
80
90
'''
81
91
Five parameter parameterization of Cochlea from (Alkhairy 2019)
82
92
'''
83
93
if xs is None :
84
94
xs = np .linspace (0 , length , 4 )
85
- cf = (lambda x : CF0 * np .exp (- x / 3.8 ))
86
- # print('cfx', cf(0))
87
- # print(bAp, np.exp(bAp*cf(0)))
95
+ cf = (lambda x : CF0 * np .exp (- x / l_factor ))
88
96
Ap_func = (lambda x : aAp * np .exp (bAp * cf (x )))
89
97
Bu_func = (lambda x : aBu * np .exp (bBu * cf (x )))
90
- cochlea = cls (types = types , Ap = [Ap_func (x ) for x in xs ], bp = bp , Bu = [Bu_func (x ) for x in xs ], gain_const = gain_const , peak_magndb = peak_magndb , CF0 = CF0 , length = length , xs = xs , rho = rho , species = None )
98
+ cochlea = cls (type = type , Ap = [Ap_func (x ) for x in xs ], bp = bp , Bu = [Bu_func (x ) for x in xs ], gain_const = gain_const , peak_magndb = peak_magndb , CF0 = CF0 , length = length , xs = xs , rho = rho , species = None , betas = betas , freqs = freqs )
91
99
cochlea .Ap_fun = Ap_func
92
100
cochlea .Bu_fun = Bu_func
93
101
return cochlea
@@ -111,23 +119,24 @@ def filter_at_location(self, x_coord, gain_const=None, peak_magndb=None, type='P
111
119
return Filter (type = type , Ap = self .Ap_fun (x_coord ), bp = self .bp_fun (x_coord ), Bu = self .Bu_fun (x_coord ), gain_const = gain_const , peak_magndb = peak_magndb , cf = self .cf (x_coord ))
112
120
113
121
def _given_species (self , species ):
114
- if species is not None :
115
- if species == 'chinchilla' :
116
- CF0 = 28.131
117
- l_factor = 3.6649
118
- length = 35
119
- elif species == 'human' :
120
- CF0 = 20.823
121
- l_factor = 7.2382
122
- length = 20
123
- # elif species == 'guinea pig' or species == 'guineapig':
124
- # elif species == 'mouse'
125
- xs = np .linspace (0 , length , 5 )[1 :]
126
- Ap = [0.3768 * np .exp (- 0.1366 * CF0 * np .exp (- x / l_factor )) for x in xs ] # this seems improbable
127
- bp = [1. , 1. , 1. , 1. ]
128
- Bu = [3.714 * np .exp (0.03123 * CF0 * np .exp (- x / l_factor )) for x in xs ] # same here
122
+ if species == 'chinchilla' : # Muller et al HR 2010
123
+ CF0 = 28.131
124
+ l_factor = 3.6649
125
+ length = 20
126
+ elif species == 'human' :
127
+ CF0 = 20.823
128
+ l_factor = 7.2382
129
+ length = 35
130
+ elif species == 'guinea pig' or species == 'guineapig' : # Tsuji and Liberman 1997 J. Comp. Neurol. 381:188-202
131
+ CF0 = 54.732
132
+ l_factor = 3.3178
133
+ length = 20
134
+ elif species == 'mouse' :
135
+ CF0 = 71.130
136
+ l_factor = 1.8566
137
+ length = 5.13
129
138
else :
130
- l_factor = 3.8
139
+ raise Exception ( f'" { species } " is an unsupported species' )
131
140
132
141
return (CF0 , l_factor , length )
133
142
@@ -191,7 +200,7 @@ def plot_impedance(self, betas=None, setting='realimag', custom_title='Normalize
191
200
show: `True` if plot is to be shown, `False` otherwise. Default is `True`.
192
201
phase_in_rad: Show phase in radians if True or in cycles otherwise
193
202
'''
194
- # plot Z and normalized Z
203
+ # plot Z and normalized Z?
195
204
if betas is None :
196
205
betas = np .linspace (0.01 , self .bp_apex * 1.5 , 10000 )
197
206
Zdata = self .Z_norm (betas )
@@ -235,7 +244,6 @@ def signal_response_heatmap(self, signal, len_xs=20, custom_title='Signal Heatma
235
244
'''
236
245
sigs = []
237
246
cfs = []
238
- # signal.plot()
239
247
for x in np .linspace (0.025 , self .cochlea_length , len_xs ):
240
248
fil = self .filter_at_location (x )
241
249
cfs += [round (self .cf (x ), 2 )]
0 commit comments