c@0
|
1 """
|
c@0
|
2 A module used for auditory analysis.
|
c@0
|
3
|
c@0
|
4 Models currently implemented:
|
c@6
|
5 * Simple frequency-modulation analysis model.
|
c@6
|
6 * Glasberg and Moore model using gammatone filters
|
c@0
|
7
|
c@0
|
8 Packaged dependencies:
|
c@6
|
9 > utils.py and/or utils.pyc
|
c@6
|
10 > erb.dat
|
c@6
|
11 > outMidFir.dat
|
c@6
|
12 > tq.dat
|
c@0
|
13
|
c@0
|
14 External dependencies:
|
c@6
|
15 > scipy
|
c@6
|
16 > numpy
|
c@6
|
17 > matplotlib
|
c@9
|
18 > sys (Built-in)
|
c@6
|
19
|
c@6
|
20 Primary functions:
|
c@9
|
21 > calc_loudness_quiet
|
c@9
|
22 > calc_loudness_noise
|
c@6
|
23 > get_excitation_i
|
c@6
|
24 > plot_excitation_response
|
c@0
|
25 """
|
c@0
|
26
|
c@5
|
27 import sys
|
c@0
|
28 import utils
|
c@0
|
29 import scipy.signal as sp
|
c@1
|
30 import scipy.fftpack as fft
|
c@0
|
31 import numpy as np
|
c@0
|
32 import matplotlib.pyplot as plt
|
c@0
|
33
|
c@9
|
34 def calc_loudness_noise(input, fs, SPL = None, inputType = 'signal', gammatoneLength=4096, rectify=False, inc_loud_region = True, verbose = False):
|
c@9
|
35 """"
|
c@9
|
36 Calculate the specifc loudness, instantaneous loudness, short term loudness and long term loudness of the input signal present in noise.
|
c@9
|
37
|
c@9
|
38 Parameters:
|
c@9
|
39 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1 or excitation pattern. (Required)
|
c@9
|
40 * fs (type: numerical) - sample frequency of the signal, input. (Required)
|
c@9
|
41 * SPL (type: float) - the sound pressure level corresponding to 1 of the normalised range -1 to 1. (Optional if inputType='excitation' then doesn't do anything. Required otherwise)
|
c@9
|
42 * inputType (type: string) - specify whether the input is the excitation pattern, or the input signal. Use 'signal' or 'excitation', respectively. (Optional; Default = 'signal')
|
c@9
|
43 * gammaToneLength (type: int) - length of gammatone filters. (Optional; Default = 4096)
|
c@9
|
44 * rectify (type = boolean) - rectify the input to model the direction shearing of the hairs in cochlea. Glasberg and Moore model doesn't consider this, so by default is false. (Optional; Default = False)
|
c@9
|
45 * inc_loud_region (type: boolean) - Specifies whether to process the high levels differently to the mid levels. (Optional; Default = False)
|
c@9
|
46 * Verbose (type: boolean) - print verbosely to stdout.
|
c@9
|
47
|
c@9
|
48 Returns:
|
c@9
|
49 * sl (type: numpy array of floats) - specific loudness
|
c@9
|
50 * loudness (type: numpy array of floats) - instantaneous loudness
|
c@9
|
51 * STL (type: numpy array of floats) - short term loudness
|
c@9
|
52 * LTL (type: numpy array of floats) - long term loudness
|
c@9
|
53 """
|
c@9
|
54
|
c@9
|
55
|
c@9
|
56 if(inputType == 'signal' or inputType == 'sig'):
|
c@9
|
57 if(SPL == None):
|
c@9
|
58 raise ValueError("You need to provide the full scale sound pressure level!")
|
c@9
|
59
|
c@9
|
60 numTracks = np.shape(input)[0]
|
c@9
|
61 lenSig = np.shape(input)[-1]
|
c@9
|
62 excitation = np.zeros((numTracks, 39, lenSig+gammatoneLength+4095))
|
c@9
|
63
|
c@9
|
64 for i in range(numTracks):
|
c@9
|
65 excitation[i] = get_excitation_i(input[i], fs, SPL, gammatoneLength=gammatoneLength, rectify = rectify, verbose = verbose)
|
c@5
|
66
|
c@9
|
67 elif(inputType == 'excitation' or inputType == 'exc'):
|
c@9
|
68 excitation = input
|
c@9
|
69 numTracks = np.shape(excitation)[0]
|
c@9
|
70 else:
|
c@9
|
71 raise ValueError("Unknown inputType. Can be 'signal' (or 'sig') or 'excitation' (or 'exc')")
|
c@9
|
72
|
c@9
|
73 del input
|
c@9
|
74
|
c@9
|
75 sl = _get_specific_loudness_noise(excitation, inc_loud_region = inc_loud_region)
|
c@9
|
76 loudness = 2*np.sum(sl,1)
|
c@9
|
77 STL = np.zeros(np.shape(loudness))
|
c@9
|
78 LTL = np.array(STL)
|
c@6
|
79
|
c@6
|
80 for i in range(numTracks):
|
c@9
|
81 STL[i] = temporal_integration(loudness[i], fs, 'STL')
|
c@9
|
82 LTL[i] = temporal_integration(STL[i], fs, 'LTL')
|
c@9
|
83
|
c@9
|
84 return sl, loudness, STL, LTL
|
c@9
|
85
|
c@9
|
86 def calc_loudness_quiet(input, fs, SPL = None, inputType = 'signal', gammatoneLength=4096, rectify = False, inc_loud_region = True, verbose = False):
|
c@9
|
87 """"
|
c@9
|
88 Calculate the specifc loudness, instantaneous loudness, short term loudness and long term loudness of the input signal.
|
c@9
|
89
|
c@9
|
90 Parameters:
|
c@9
|
91 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1 or excitation pattern. (Required)
|
c@9
|
92 * fs (type: numerical) - sample frequency of the signal, input. (Required)
|
c@9
|
93 * SPL (type: float) - the sound pressure level corresponding to 1 of the normalised range -1 to 1. (Optional if inputType='excitation' then doesn't do anything. Required otherwise)
|
c@9
|
94 * inputType (type: string) - specify whether the input is the excitation pattern, or the input signal. Use 'signal' or 'excitation', respectively. (Optional; Default = 'signal')
|
c@9
|
95 * gammaToneLength (type: int) - length of gammatone filters. (Optional; Default = 4096)
|
c@9
|
96 * rectify (type = boolean) - rectify the input to model the direction shearing of the hairs in cochlea. Glasberg and Moore model doesn't consider this, so by default is false. (Optional; Default = False)
|
c@9
|
97 * inc_loud_region (type: boolean) - Specifies whether to process the high levels differently to the mid levels. (Optional; Default = False)
|
c@9
|
98 * Verbose (type: boolean) - print verbosely to stdout.
|
c@9
|
99
|
c@9
|
100 Returns:
|
c@9
|
101 * sl (type: numpy array of floats) - specific loudness
|
c@9
|
102 * loudness (type: numpy array of floats) - instantaneous loudness
|
c@9
|
103 * STL (type: numpy array of floats) - short term loudness
|
c@9
|
104 * LTL (type: numpy array of floats) - long term loudness
|
c@9
|
105 """
|
c@6
|
106
|
c@9
|
107
|
c@9
|
108 if(inputType == 'signal' or inputType == 'sig'):
|
c@9
|
109 if(SPL == None):
|
c@9
|
110 raise ValueError("You need to provide the full scale sound pressure level!")
|
c@9
|
111 excitation = get_excitation_i(input, fs, SPL, gammatoneLength=gammatoneLength, rectify = rectify, verbose = verbose)
|
c@9
|
112 elif(inputType == 'excitation' or inputType == 'exc'):
|
c@9
|
113 excitation = input
|
c@9
|
114 else:
|
c@9
|
115 raise ValueError("Unknown inputType. Can be 'signal' (or 'sig') or 'excitation' (or 'exc')")
|
c@5
|
116
|
c@9
|
117 del input
|
c@5
|
118
|
c@9
|
119 sl = _get_specific_loudness_quiet(excitation, inc_loud_region = inc_loud_region)
|
c@9
|
120 loudness = 2*np.sum(sl,0)
|
c@9
|
121 STL = temporal_integration(loudness, fs, 'STL')
|
c@9
|
122 LTL = temporal_integration(STL, fs, 'LTL')
|
c@6
|
123
|
c@9
|
124 return sl, loudness, STL, LTL
|
c@5
|
125
|
c@9
|
126 def _get_specific_loudness_noise(exc_i, analyse = "all", inc_loud_region = True):
|
c@0
|
127 """
|
c@9
|
128 A function to calculate the specific loudness of the excitation patterns at each ERB when present in noise. Specific loudness is calculated for three regions of signal intensity, low level, mid level and high level. The high level processing is optional, and by default, ignored. When ignored the high level region is processed equivalent to that of the mid region.
|
c@6
|
129
|
c@9
|
130 Parameters:
|
c@9
|
131 * exc_i (type: array-like of floats) - an array of shape (39, lenSig) of the excitation intensity of the signal. The outer dimension determines the ERB channel. (Required)
|
c@9
|
132 * inc_loud_region (type: boolean) - Specifies whether to process the high levels differently to the mid levels. (Optional; Default = False)
|
c@9
|
133 """
|
c@6
|
134 exc_i = np.array(exc_i)
|
c@6
|
135
|
c@6
|
136 lenSig = np.shape(exc_i)[-1] #length signal
|
c@6
|
137 numTracks = np.shape(exc_i)[0]
|
c@9
|
138 tq, G, A, alpha = _get_specific_loudness_parameters(lenSig)
|
c@9
|
139 K = _calc_k_parameter(lenSig)
|
c@6
|
140 specific_loudness = exc_low = exc_mid = exc_high = np.zeros(np.shape(exc_i))
|
c@6
|
141
|
c@6
|
142 exc_signoise = sum(exc_i, 0)
|
c@9
|
143 signoise_gt_tl = _get_greater_than_tl(exc_signoise) #boolean array of elements greater than the loud threshold
|
c@6
|
144 signoise_lt_tl = ~signoise_gt_tl
|
c@6
|
145
|
c@7
|
146 if analyse.lower() == "all":
|
c@7
|
147 loop = range(numTracks);
|
c@7
|
148 elif analyse.lower() == "first":
|
c@7
|
149 loop = range(1)
|
c@6
|
150
|
c@6
|
151 for i in loop:
|
c@6
|
152
|
c@6
|
153 exc_sig = exc_i[i]
|
c@6
|
154 exc_noise = exc_signoise - exc_sig
|
c@6
|
155 tn = K*exc_noise + tq
|
c@6
|
156
|
c@9
|
157 less_than_tn = _get_less_than_tq(exc_sig, tn) #boolean array of elements less than or equal to the threshold of quiet
|
c@8
|
158 greater_than_tn = ~less_than_tn #boolean array of elements greater than the threshold of quiet
|
c@6
|
159
|
c@6
|
160 if inc_loud_region:
|
c@7
|
161 c1 = signoise_lt_tl * greater_than_tn #case 1
|
c@7
|
162 c2 = signoise_lt_tl * less_than_tn #case 2
|
c@7
|
163 c3 = signoise_gt_tl * greater_than_tn #case 3
|
c@8
|
164 c4 = signoise_gt_tl * less_than_tn #case 4
|
c@9
|
165 specific_loudness[i, c3] = _get_specific_loudness_noise_c3(exc_sig[c3], exc_noise[c3], tq[c3], tn[c3], G[c3], A[c3], alpha[c3])
|
c@9
|
166 specific_loudness[i, c4] = _get_specific_loudness_noise_c4(exc_sig[c4], exc_noise[c4], tq[c4], tn[c4], G[c4], A[c4], alpha[c4])
|
c@6
|
167 else:
|
c@8
|
168 c1 = greater_than_tn #case 1
|
c@8
|
169 c2 = less_than_tn #case 2
|
c@6
|
170
|
c@9
|
171 specific_loudness[i][c1] = _get_specific_loudness_noise_c1(exc_sig[c1], exc_noise[c1], tq[c1], tn[c1], G[c1], A[c1], alpha[c1])
|
c@9
|
172 specific_loudness[i][c2] = _get_specific_loudness_noise_c2(exc_sig[c2], exc_noise[c2], tq[c2], tn[c2], G[c2], A[c2], alpha[c2])
|
c@6
|
173
|
c@6
|
174 return specific_loudness
|
c@6
|
175
|
c@9
|
176 def _get_specific_loudness_noise_c1(exc_sig, exc_noise, tq, tn, G, A, alpha):
|
c@6
|
177 """
|
c@9
|
178 A function to calculate the specific loudness of a component of the signal for the case exc_noise < 10**10, and exc_quiet > threshold noise (c1).
|
c@9
|
179
|
c@9
|
180 Parameters:
|
c@9
|
181 * tq (type: numpy array of floats) - the threshold of quiet for each centre frequency of the ERBs
|
c@9
|
182 * tn (type: numpy array of floats) - the threshold of quiet when present in noise for each centre frequency of the ERBs
|
c@9
|
183 * G (type: numpy array of floats) - the frequency dependent gain values for each centre frequency of the ERBs
|
c@9
|
184 * A (type: numpy array of floats) - the frequency dependent A values for each centre frequency of the ERBs
|
c@9
|
185 * alpha (type: numpy array of floats) - the frequency dependent alpha values for each centre frequency of the ERBs
|
c@9
|
186
|
c@9
|
187 Returns:
|
c@9
|
188 * specific_loudness_c1 (type: array-like matrix of floats) - An array with dimensions equal to the exc_sig containing the
|
c@9
|
189 specific loudness c1.
|
c@6
|
190 """
|
c@6
|
191 C = 0.046871 #constant parameter
|
c@6
|
192 sl_c1 = C*(((exc_sig + exc_noise)*G + A)**alpha - A**alpha) - C*((((tn + exc_noise)*G + A)**alpha) - (tq*G + A)**alpha) * (tn/exc_sig)**0.3
|
c@6
|
193
|
c@6
|
194 return sl_c1
|
c@6
|
195
|
c@9
|
196 def _get_specific_loudness_noise_c2(exc_sig, exc_noise, tq, tn, G, A, alpha):
|
c@6
|
197 """
|
c@9
|
198 A function to calculate the specific loudness of a component of the signal for the case exc_noise < 10**10, and exc_quiet < threshold noise (c2).
|
c@9
|
199
|
c@6
|
200 Parameters:
|
c@9
|
201 * tq (type: numpy array of floats) - the threshold of quiet for each centre frequency of the ERBs
|
c@9
|
202 * tn (type: numpy array of floats) - the threshold of quiet when present in noise for each centre frequency of the ERBs
|
c@9
|
203 * G (type: numpy array of floats) - the frequency dependent gain values for each centre frequency of the ERBs
|
c@9
|
204 * A (type: numpy array of floats) - the frequency dependent A values for each centre frequency of the ERBs
|
c@9
|
205 * alpha (type: numpy array of floats) - the frequency dependent alpha values for each centre frequency of the ERBs
|
c@9
|
206
|
c@9
|
207 Returns:
|
c@9
|
208 * specific_loudness_c2 (type: array-like matrix of floats) - An array with dimensions equal to the exc_sig containing the
|
c@9
|
209 specific loudness c2.
|
c@6
|
210 """
|
c@6
|
211
|
c@6
|
212 C = 0.046871 #constant parameter
|
c@7
|
213 sl_c2 = (C*((2*exc_sig)/(exc_sig + tn))**1.5) * (((tq*G + A)**alpha - A**alpha)/(((0.0 + tn + exc_noise)*G + A)**alpha - (exc_noise*G + A)**alpha)) * (((exc_sig + exc_noise)*G + A)**alpha - (exc_noise*G + A)**alpha)
|
c@6
|
214
|
c@6
|
215 return sl_c2
|
c@6
|
216
|
c@9
|
217 def _get_specific_loudness_noise_c3(exc_sig, exc_noise, tq, tn, G, A, alpha):
|
c@9
|
218 """
|
c@9
|
219 A function to calculate the specific loudness of a component of the signal for the case exc_noise > 10**10, and exc_quiet > threshold noise (c3).
|
c@6
|
220
|
c@9
|
221 Parameters:
|
c@9
|
222 * tq (type: numpy array of floats) - the threshold of quiet for each centre frequency of the ERBs
|
c@9
|
223 * tn (type: numpy array of floats) - the threshold of quiet when present in noise for each centre frequency of the ERBs
|
c@9
|
224 * G (type: numpy array of floats) - the frequency dependent gain values for each centre frequency of the ERBs
|
c@9
|
225 * A (type: numpy array of floats) - the frequency dependent A values for each centre frequency of the ERBs
|
c@9
|
226 * alpha (type: numpy array of floats) - the frequency dependent alpha values for each centre frequency of the ERBs
|
c@9
|
227
|
c@9
|
228 Returns:
|
c@9
|
229 * specific_loudness_c3 (type: array-like matrix of floats) - An array with dimensions equal to the exc_sig containing the
|
c@9
|
230 specific loudness c3.
|
c@9
|
231 """
|
c@6
|
232 C = 0.046871 #constant parameter
|
c@6
|
233 C2 = C/((1.04 * 10**6)**0.5)
|
c@6
|
234 sl_c3 = (C2*(exc_sig + exc_noise)**0.5) - C2*((tn + exc_noise)**0.5 - (tq*G + A)**alpha + A**alpha) * (tn/exc_sig)**0.3
|
c@6
|
235
|
c@6
|
236 return sl_c3
|
c@6
|
237
|
c@9
|
238 def _get_specific_loudness_noise_c4(exc_sig, exc_noise, tq, tn, G, A, alpha):
|
c@9
|
239 """
|
c@9
|
240 A function to calculate the specific loudness of a component of the signal for the case exc_noise > 10**10, and exc_quiet < threshold noise (c4).
|
c@6
|
241
|
c@9
|
242 Parameters:
|
c@9
|
243 * tq (type: numpy array of floats) - the threshold of quiet for each centre frequency of the ERBs
|
c@9
|
244 * tn (type: numpy array of floats) - the threshold of quiet when present in noise for each centre frequency of the ERBs
|
c@9
|
245 * G (type: numpy array of floats) - the frequency dependent gain values for each centre frequency of the ERBs
|
c@9
|
246 * A (type: numpy array of floats) - the frequency dependent A values for each centre frequency of the ERBs
|
c@9
|
247 * alpha (type: numpy array of floats) - the frequency dependent alpha values for each centre frequency of the ERBs
|
c@9
|
248
|
c@9
|
249 Returns:
|
c@9
|
250 * specific_loudness_c4 (type: array-like matrix of floats) - An array with dimensions equal to the exc_sig containing the
|
c@9
|
251 specific loudness c4.
|
c@9
|
252
|
c@9
|
253 """
|
c@6
|
254 C = 0.046871 #constant parameter
|
c@6
|
255 sl_c4 = (C*((2*exc_sig)/(exc_sig + tn))**1.5) * (((tq*G + A)**alpha - A**alpha)/((tn + exc_noise)**0.5 - (exc_noise)**0.5)) * ((exc_sig + exc_noise)**0.5 - (exc_noise)**0.5)
|
c@6
|
256
|
c@6
|
257 return sl_c4
|
c@6
|
258
|
c@9
|
259 def _get_specific_loudness_quiet(exc_i, inc_loud_region = True):
|
c@6
|
260 """
|
c@6
|
261 A function to calculate the specific loudness of the excitation patterns at each ERB. Specific loudness is calculated for three regions of signal intensity, low level, mid level and high level. The high level processing is optional, and by default, ignored. When ignored the high level region is processed equivalent to that of the mid region.
|
c@3
|
262
|
c@3
|
263 Parameters:
|
c@6
|
264 * exc_i (type: array-like of floats) - an array of shape (39, lenSig) of the excitation intensity of the signal. The outer dimension determines the ERB channel. (Required)
|
c@3
|
265 * inc_loud_region (type: boolean) - Specifies whether to process the high levels differently to the mid levels. (Optional; Default = False)
|
c@9
|
266
|
c@9
|
267 Returns:
|
c@9
|
268 * specific_loudness (type: array-like matrix of floats) - specific loudness
|
c@0
|
269 """
|
c@3
|
270 exc_i = np.array(exc_i)
|
c@3
|
271
|
c@1
|
272 lenSig = np.shape(exc_i)[-1] #length signal
|
c@9
|
273 tq, G, A, alpha = _get_specific_loudness_parameters(lenSig)
|
c@1
|
274 specific_loudness = exc_low = exc_mid = exc_high = np.zeros(np.shape(exc_i))
|
c@0
|
275
|
c@9
|
276 less_than_tq = _get_less_than_tq(exc_i, tq) #boolean array of elements less than or equal to the threshold of quiet
|
c@1
|
277 greater_than_tq = ~less_than_tq #boolean array of elements greater than the threshold of quiet
|
c@9
|
278 greater_than_tl = _get_greater_than_tl(exc_i) #boolean array of elements greater than the loud threshold
|
c@8
|
279 gttq_lttl = greater_than_tq * ~greater_than_tl #boolean array of elements greater than the threshold of quiet but less than the threshold of loud
|
c@0
|
280
|
c@1
|
281 exc_low = exc_i[less_than_tq]
|
c@9
|
282 specific_loudness[less_than_tq] = _get_specific_loudness_low(exc_low, G[less_than_tq], tq[less_than_tq], A[less_than_tq], alpha[less_than_tq])
|
c@1
|
283
|
c@1
|
284 if(inc_loud_region):
|
c@1
|
285 exc_mid = exc_i[gttq_lttl]
|
c@1
|
286 exc_high = exc_i[greater_than_tl]
|
c@9
|
287 specific_loudness[gttq_lttl] = _get_specific_loudness_mid(exc_mid, G[gttq_lttl], A[gttq_lttl], alpha[gttq_lttl])
|
c@9
|
288 specific_loudness[greater_than_tl] = _get_specific_loudness_high(exc_high)
|
c@1
|
289 else:
|
c@1
|
290 exc_mid = exc_i[greater_than_tq]
|
c@9
|
291 specific_loudness[greater_than_tq] = _get_specific_loudness_mid(exc_mid, G[greater_than_tq], A[greater_than_tq], alpha[greater_than_tq])
|
c@1
|
292
|
c@1
|
293 return specific_loudness
|
c@0
|
294
|
c@9
|
295 def _get_specific_loudness_parameters(lenSig = 1):
|
c@3
|
296 """
|
c@6
|
297 Loads and returns the specific loudness values. If lenSig is specified, the parameters are shaped equal to the excitation signal to allow for matrix elementwise operations between the parameters and signal. (Assumes excitation signal shape is [39, lenSig]).
|
c@3
|
298
|
c@3
|
299 Parameters:
|
c@3
|
300 * lenSig (type: numerical int) - the length of the excitation signal to be analysed. (Optional; Default = 1)
|
c@3
|
301
|
c@3
|
302 Returns:
|
c@3
|
303 * tq (type: numpy array of floats) - the threshold of quiet for each centre frequency of the ERBs
|
c@3
|
304 * G (type: numpy array of floats) - the frequency dependent gain values for each centre frequency of the ERBs
|
c@3
|
305 * A (type: numpy array of floats) - the frequency dependent A values for each centre frequency of the ERBs
|
c@3
|
306 * alpha (type: numpy array of floats) - the frequency dependent alpha values for each centre frequency of the ERBs
|
c@3
|
307 """
|
c@3
|
308
|
c@3
|
309 tq_dB, A, alpha = utils.load_sl_parameters() #load tq, A and alpha parameters
|
c@3
|
310 tq_dB = np.transpose(np.tile(tq_dB, (lenSig,1)))
|
c@3
|
311 tq = 10**(tq_dB / 10)
|
c@3
|
312 A = np.transpose(np.tile(A, (lenSig,1)))
|
c@3
|
313 alpha = np.transpose(np.tile(alpha, (lenSig,1)))
|
c@3
|
314 tq500_dB = 3.73 #threshold of quiet at 500Hz reference
|
c@3
|
315 G = 10**((tq500_dB - tq_dB)/10) #gain parameters
|
c@3
|
316
|
c@3
|
317 return tq, G, A, alpha
|
c@3
|
318
|
c@9
|
319 def _calc_k_parameter(lenSig = 1):
|
c@6
|
320 """
|
c@9
|
321 A function to return the K parameter of the loudness compression curve.
|
c@9
|
322
|
c@9
|
323 Parameters:
|
c@9
|
324 * lenSig (type: int): use if want to shape to the input data for matrix multiplication. (Optional; Default = 1)
|
c@9
|
325
|
c@9
|
326 Returns:
|
c@9
|
327 * K (type: numpy array of floats) - a parameter to the loudness compression curve
|
c@6
|
328 """
|
c@6
|
329 nerbs = 39
|
c@6
|
330 erbs = np.array(range(1,nerbs+1))
|
c@6
|
331 fc = (10**(erbs/21.366)-1)/0.004368
|
c@6
|
332
|
c@6
|
333 fkRef = 10**np.append(np.append(np.array(1), np.linspace(np.log10(50), np.log10(500), 11)), np.linspace(3,4.5,16))
|
c@6
|
334 kRef = np.append(np.append(13, np.linspace(13,-3,11)), np.ones((1,16))*-3)
|
c@6
|
335 K = np.interp(fc,fkRef,kRef)
|
c@8
|
336 K = 10**(K/10)
|
c@6
|
337 K = np.transpose(np.tile(K, (lenSig,1)))
|
c@6
|
338
|
c@6
|
339 return K
|
c@6
|
340
|
c@9
|
341 def _get_specific_loudness_low(exc_low, G, tq, A, alpha):
|
c@3
|
342 """
|
c@9
|
343 Returns the specific loudness of the low level parts of the signal. Use _get_specific_loudness_parameters() and specify lenSig
|
c@9
|
344 to obtain the correct values for G, tq, A and alpha. Use _get_less_than_tq() to find the indexes of the samples with lower level
|
c@3
|
345 excitations.
|
c@3
|
346
|
c@6
|
347 EXAMPLE USE
|
c@3
|
348
|
c@3
|
349 # exc_i is the excitation intensity
|
c@3
|
350 lenSig = np.shape(exc_i)[-1] # find the length of the signal
|
c@9
|
351 tq, G, A, alpha = _get_specific_loudness_parameters(lenSig) # get the shaped loudness parameters
|
c@9
|
352 less_than_tq = _get_less_than_tq(exc_i, tq) # find which samples are lower level
|
c@9
|
353 specific_loudness[less_than_tq] = _get_specific_loudness_low(exc_low[less_than_tq], G[less_than_tq], tq[less_than_tq], A[less_than_tq], alpha[less_than_tq])
|
c@3
|
354 # only process the low level part of the signal
|
c@3
|
355
|
c@3
|
356 Parameters:
|
c@3
|
357 * exc_low (type: array-like matrix of floats) - the lower level (less than or equal to tq) excitation pattern for each ERB
|
c@3
|
358 (Required)
|
c@3
|
359 * G (type: array-like matrix of floats) - the frequency dependent loudness gain parameters for each ERB, must be same shape
|
c@3
|
360 as exc_low. (Required)
|
c@3
|
361 * tq (type: array-like matrix of floats) - the frequency dependent threshold of quiet parameters for each ERB. Must be same
|
c@3
|
362 shape as exc_low. (Required)
|
c@3
|
363 * A (type: array-like matrix of floats) - the frequency dependent A parameters for each ERB. Must be same shape as exc_low.
|
c@3
|
364 * alpha (type: array-like matrix of floats) - the frequency dependent alpha parameters for each ERB. Must be same shape as
|
c@3
|
365 exc_low. (Required)
|
c@3
|
366
|
c@3
|
367 Returns:
|
c@3
|
368 * specific_loudness_low (type: array-like matrix of floats) - An array with dimensions equal to the exc_low containing the
|
c@3
|
369 specific loudness of the signal at levels below the threshold of quiet.
|
c@3
|
370 """
|
c@1
|
371
|
c@5
|
372 C = 0.046871 #constant parameter
|
c@5
|
373 specific_loudness_low = C * ((2.0*exc_low)/(0.0+exc_low+tq))**1.5 * ((G * exc_low + A)**alpha - A**alpha)
|
c@1
|
374
|
c@1
|
375 return specific_loudness_low
|
c@1
|
376
|
c@9
|
377 def _get_specific_loudness_mid(exc_mid, G, A, alpha):
|
c@3
|
378 """
|
c@3
|
379 Returns the specific loudness of the mid level parts of the signal.
|
c@3
|
380
|
c@6
|
381 EXAMPLE USE
|
c@3
|
382
|
c@3
|
383 # exc_i is the excitation intensity
|
c@3
|
384 lenSig = np.shape(exc_i)[-1] # find the length of the signal
|
c@9
|
385 tq, G, A, alpha = _get_specific_loudness_parameters(lenSig) # get the shaped loudness parameters
|
c@9
|
386 less_than_tq = _get_less_than_tq(exc_i, tq) # find which samples are lower level
|
c@3
|
387 greater_than_tq = ~less_than_tq # find which samples are greater than the threshold of quiet
|
c@9
|
388 greater_than_tl = _get_greater_than_tl(exc_i) # find which samples are greater than the loud threshold
|
c@3
|
389 gttq_lttl = greater_than_tq[~greater_than_tl] # find which samples are mid level
|
c@9
|
390 specific_loudness[gttq_lttl] = _get_specific_loudness_low(exc_low[gttq_lttl], G[gttq_lttl], tq[gttq_lttl], A[gttq_lttl], alpha[gttq_lttl])
|
c@3
|
391 # only process the mid level part of the signal
|
c@3
|
392
|
c@6
|
393 NOTE: The above is an example of use assuming the higher level processing IS NOT IGNORED. Use variable greater_than_tq if processing higher levels equivalent to the mid.
|
c@3
|
394
|
c@3
|
395
|
c@3
|
396 Parameters:
|
c@3
|
397 * exc_mid (type: array-like matrix of floats) - the mid level (larger than tq (and, optionally less than high level threshold))
|
c@3
|
398 excitation pattern for each ERB (Required)
|
c@6
|
399 * G (type: array-like matrix of floats) - the frequency dependent loudness gain parameters for each ERB, must be same shape as exc_low. (Required)
|
c@3
|
400 * A (type: array-like matrix of floats) - the frequency dependent A parameters for each ERB. Must be same shape as exc_low.
|
c@6
|
401 * alpha (type: array-like matrix of floats) - the frequency dependent alpha parameters for each ERB. Must be same shape as exc_low. (Required)
|
c@3
|
402
|
c@3
|
403 Returns:
|
c@6
|
404 * specific_loudness_mid (type: array-like matrix of floats) - An array with dimensions equal to the exc_mid containing the specific loudness of the signal at mid levels.
|
c@3
|
405 """
|
c@1
|
406
|
c@6
|
407 C = 0.046871 #constant parameter
|
c@5
|
408 specific_loudness_mid = C * ((G * exc_mid + A)**alpha - (A**alpha))
|
c@1
|
409
|
c@1
|
410 return specific_loudness_mid
|
c@1
|
411
|
c@9
|
412 def _get_specific_loudness_high(exc_high):
|
c@1
|
413 """
|
c@3
|
414 Returns the specific loudness of the high level parts of the signal.
|
c@3
|
415
|
c@6
|
416 EXAMPLE USE
|
c@3
|
417
|
c@3
|
418 # exc_i is the excitation intensity
|
c@3
|
419 lenSig = np.shape(exc_i)[-1] # find the length of the signal
|
c@9
|
420 tq, G, A, alpha = _get_specific_loudness_parameters(lenSig) # get the shaped loudness parameters
|
c@9
|
421 greater_than_tl = _get_greater_than_tl(exc_i) # find which samples are greater than the loud threshold
|
c@9
|
422 specific_loudness[greater_than_tl] = _get_specific_loudness_low(exc_low[greater_than_tl], G[greater_than_tl], tq[greater_than_tl], A[greater_than_tl], alpha[greater_than_tl])
|
c@3
|
423 # only process the mid level part of the signal
|
c@3
|
424
|
c@3
|
425 Parameters:
|
c@3
|
426 * exc_high (type: array-like matrix of floats) - the high level (larger than the threshold of high level) excitation pattern
|
c@3
|
427 for each ERB (Required)
|
c@3
|
428
|
c@3
|
429 Returns:
|
c@6
|
430 * specific_loudness_high (type: array-like matrix of floats) - An array with dimensions equal to the exc_high containing the specific loudness of the signal at high levels.
|
c@1
|
431 """
|
c@1
|
432
|
c@6
|
433 C = 0.046871 #constant parameter
|
c@1
|
434 specific_loudness_high = C * (exc_high / (1.04 * 10**6))**0.5
|
c@1
|
435
|
c@1
|
436 return specific_loudness_high
|
c@1
|
437
|
c@9
|
438 def _get_greater_than_tl(exc_i):
|
c@1
|
439 """
|
c@1
|
440 A function to return if each element of the excitation intensity is greater than the threshold of loud.
|
c@1
|
441
|
c@1
|
442 Parameters:
|
c@1
|
443 * exc_i (type: array-like matrix of floats) - the input excitation intensity
|
c@1
|
444
|
c@1
|
445 Returns:
|
c@6
|
446 * le_tq (type: array-like matrix of booleans) - a boolean array with dimensions equal to the input specifying if the excitation intensity is greater than the threshold of loud
|
c@1
|
447 """
|
c@1
|
448
|
c@1
|
449 lenSig = np.shape(exc_i)[-1]
|
c@1
|
450 g_tl = exc_i[:,:]>np.transpose(np.tile(10**10,(lenSig,39)))
|
c@1
|
451
|
c@1
|
452 return g_tl
|
c@1
|
453
|
c@9
|
454 def _get_less_than_tq(exc_i, tq):
|
c@1
|
455 """
|
c@1
|
456 A function to return if each element of the excitation intensity is less than the threshold of quiet.
|
c@1
|
457
|
c@1
|
458 Parameters:
|
c@1
|
459 * exc_i (type: array-like matrix of floats) - the input excitation intensity
|
c@1
|
460 * tq (type: array-like matrix of floats) - the threshold of quiet for each ERB.
|
c@1
|
461
|
c@1
|
462 Returns:
|
c@6
|
463 * le_tq (type: array-like matrix of booleans) - a boolean array with dimensions equal to the input specifying if the excitation intensity is less than the threshold of quiet
|
c@1
|
464 """
|
c@1
|
465
|
c@1
|
466 if (np.shape(exc_i)!=np.shape(tq)):
|
c@1
|
467 np.transpose(np.tile(exc_i,(np.shape(exc_i)[-1],1)))
|
c@1
|
468
|
c@1
|
469 le_tq = exc_i<=tq
|
c@1
|
470
|
c@1
|
471 return le_tq
|
c@1
|
472
|
c@9
|
473 def get_excitation_i(input, fs, SPL, gammatoneLength=4096, rectify=False, verbose = False):
|
c@0
|
474 """
|
c@0
|
475 A function to calculate the excitation intensity of the input signal.
|
c@0
|
476
|
c@0
|
477 Parameters:
|
c@0
|
478 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required)
|
c@0
|
479 * fs (type: numerical) - sample frequency of the signal, input. (Required)
|
c@6
|
480 * SPL (type: double) - the sound pressure level (SPL) at 0 dBFS, e.g., the SPL of a sine wave with peaks at amplitude 1 and troughs at amplitude -1. (Required)
|
c@6
|
481 * rectify (type: boolean) - Specifies whether to include half wave rectification, modelling the direction of that the cochlear nerves vibrate. True to include, False to ignore. (Optional; Default = False)
|
c@0
|
482
|
c@0
|
483 Returns:
|
c@6
|
484 * gtfs (type: numpy array of floats) - array with size ((39,) + np.shape(input)) containing the excitation pattern (in sound intensity) for each ERB of input signal. The excitation pattern for the nth ERB can be accessed with gtfs[n].
|
c@0
|
485 """
|
c@0
|
486
|
c@0
|
487 input = np.array(input)
|
c@5
|
488
|
c@9
|
489 input = v_Pascal(input, SPL)
|
c@5
|
490
|
c@9
|
491 excitation = outMidFir(input)
|
c@5
|
492
|
c@9
|
493 b = gammatone_filter(fs, filterLength=gammatoneLength, normalise = True)
|
c@9
|
494 excitation = filterbank_decomposition(excitation, b, verbose = verbose)
|
c@5
|
495
|
c@0
|
496 if (rectify):
|
c@9
|
497 excitation = half_rectification(excitation)
|
c@5
|
498
|
c@9
|
499 excitation = pa_i(excitation)
|
c@9
|
500 excitation = at_normalise(excitation)
|
c@0
|
501
|
c@9
|
502 return excitation
|
c@5
|
503
|
c@9
|
504 def plot_excitation_response(input = None, fs = 44100, outMidFilt = True, nyquist=True, gammatone = True, gammatoneLength=4096, xscale = 'log', yscale = 'log'):
|
c@0
|
505 """
|
c@0
|
506 A function that plots the transfer function of the outer middle ear and each gammatone filter.
|
c@0
|
507
|
c@0
|
508 Parameters:
|
c@0
|
509 * fs (type: numerical) - the sampling frequency of the signal. (Optional; Default = 44100)
|
c@0
|
510 * outMidFilt (type: boolean) - filter the signal by the outer and middle ear FIR filter. (Optional; Default = True)
|
c@0
|
511 * xscale (type: string) - the scale of the frequency axis. Values are 'log' or 'linear'. (Optional; Default = 'log')
|
c@0
|
512 * yscale (type: string) - the scale of the amplitude axis. Values are 'log' or 'linear'. (Optional; Default = 'log')
|
c@0
|
513 """
|
c@1
|
514
|
c@4
|
515 if input == None:
|
c@4
|
516 input = np.zeros((np.ceil(fs)))
|
c@1
|
517 input[0] = 1
|
c@4
|
518
|
c@0
|
519 if(outMidFilt): input = outMidFir(input)
|
c@4
|
520 if(gammatone):
|
c@9
|
521 b = gammatone_filter(fs, filterLength=gammatoneLength, normalise = True)
|
c@9
|
522 input = filterbank_decomposition(input, b)
|
c@6
|
523 #input = holdsworth_gammatone_filter(input,fs)
|
c@4
|
524 numPlot = range(np.shape(input)[0])
|
c@4
|
525 else:
|
c@4
|
526 numPlot = (0,)
|
c@4
|
527 input = input.reshape(1,len(input))
|
c@4
|
528
|
c@4
|
529 for i in numPlot:
|
c@9
|
530 utils.plot_fft(input[i],xscale, yscale, nyquist=True, show=False)
|
c@0
|
531
|
c@0
|
532 plt.show()
|
c@0
|
533
|
c@4
|
534 return
|
c@0
|
535
|
c@0
|
536 def get_modulation_i(input, fs):
|
c@0
|
537 """
|
c@6
|
538 A function to calculate the modulation intensity of the input intensity signal. The function implements a filter bank of bandpass filters with cut off frequencies ranging from 0.25 to 16 Hz.
|
c@0
|
539
|
c@0
|
540 Parameters:
|
c@0
|
541 * input (type: array-like matrix of floats) - the input intensity signal.
|
c@0
|
542 E.g., use get_excitation_i() to obtain excitation intensity and use as input.
|
c@0
|
543 * fs (type: numerical) - sampling frequency of input signal
|
c@0
|
544
|
c@0
|
545 Returns:
|
c@6
|
546 * y (type: numpy array of floats) - array with size ((10,) + np.shape(input)) containing the modulation intensity of the signal at each modulation filter. The modulation intensity for the nth filter can be accessed with y[n].
|
c@0
|
547 """
|
c@0
|
548
|
c@0
|
549 input = np.array(input)
|
c@0
|
550 b = fir_antialias(fs)
|
c@0
|
551 input_lp = sp.lfilter(b,(1),input_fr)
|
c@0
|
552 input_ds = downsample(input_lp, fs)
|
c@0
|
553 fc = np.array(utils.exp_sequence(-2,4,10))
|
c@0
|
554 bw = fc/2
|
c@9
|
555 y = filterbank_decomposition(input_ds, fs, fc, bw)
|
c@0
|
556
|
c@0
|
557 return y
|
c@0
|
558
|
c@0
|
559 def outMidFir(input):
|
c@0
|
560 """
|
c@0
|
561 A function to filter the input signal with the response of the outer and middle ear.
|
c@0
|
562
|
c@0
|
563 Parameters:
|
c@0
|
564 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required)
|
c@0
|
565
|
c@0
|
566 Returns:
|
c@6
|
567 * y (type: numpy array of floats) - array with dimensions equal to the input signal filtered by the response of the outer and middle ear.
|
c@0
|
568 """
|
c@0
|
569
|
c@0
|
570 input = np.array(input)
|
c@0
|
571 b = utils.load_outMidFir_coeff()
|
c@9
|
572 y = sp.fftconvolve(input, b)
|
c@9
|
573
|
c@0
|
574 return y
|
c@0
|
575
|
c@9
|
576 def gammatone_filter(fs, filterLength=4096, normalise = True):
|
c@0
|
577 """
|
c@6
|
578 A function to return the filter coefficients of 39 different gammatones with fc of ERBs 1 to 39.
|
c@0
|
579
|
c@0
|
580 Parameters:
|
c@0
|
581 * fs (type: numerical) - sample frequency of the signal, input. (Required)
|
c@9
|
582 * filterLength (type: int) - length of the filters (Optional; Default = True)
|
c@9
|
583 * normalise (type: boolean) - normalise peaks to united (Optional; Default = True)
|
c@0
|
584
|
c@0
|
585 Returns:
|
c@9
|
586 * b (type: numpy array of floats) - array with size ((39),np.shape(input)) containing the impulse response of the signal at each gammatone filter. The response at the bth gammatone filter can be accessed by y[n].
|
c@0
|
587 """
|
c@0
|
588
|
c@4
|
589 nerbs = 39
|
c@4
|
590 erbs = np.array(range(1,nerbs+1))
|
c@4
|
591 fc = (10**(erbs/21.366)-1)/0.004368
|
c@4
|
592 bw = 24.673 * (1 + 0.004368*fc)
|
c@4
|
593 N = 4
|
c@4
|
594 t = 1.0*np.array(range(filterLength))/fs
|
c@4
|
595
|
c@4
|
596 b = np.zeros((nerbs,filterLength))
|
c@4
|
597
|
c@4
|
598 for i in range(39):
|
c@7
|
599 b[i] = t**(N-1) * np.exp(-2*np.pi*bw[i]*t) * np.cos(2*np.pi*fc[i]*t)
|
c@4
|
600
|
c@7
|
601 if normalise:
|
c@7
|
602 A = 1/(np.abs(fft.fft(b[i], 4*filterLength))).max()
|
c@7
|
603 b[i] *= A
|
c@7
|
604
|
c@4
|
605 return b
|
c@4
|
606
|
c@9
|
607 def _holdsworth_gammatone_filter(input, fs):
|
c@4
|
608 """
|
c@9
|
609 Feed the input through a bank of gammatone filters, Holdsworth implementation. Not sure how great this works, don't use.
|
c@4
|
610
|
c@9
|
611 Parameters:
|
c@9
|
612 * input (type: array-like matrix of floats) - signal. (Required)
|
c@9
|
613 * fs (type: numerical) - sample frequency of the signal, input. (Required)
|
c@9
|
614
|
c@9
|
615 Returns:
|
c@9
|
616 * out (type: numpy array of floats) - array with size ((39),np.shape(input)) containing the output of the signal at each gammatone filter.
|
c@4
|
617 """
|
c@0
|
618 input = np.array(input)
|
c@4
|
619 input = input + 0j
|
c@4
|
620
|
c@4
|
621 T = 1.0/fs
|
c@4
|
622
|
c@4
|
623 ERBs = np.array(range(1,40))
|
c@4
|
624 f0 = (10**(ERBs/21.4)-1)/4.37e-3
|
c@4
|
625
|
c@4
|
626 inLen = len(input)
|
c@4
|
627 b = 24.673 * (1 + 0.004368*f0)
|
c@4
|
628 k = np.array(range(inLen)) + 0j
|
c@4
|
629 out = np.zeros((39,inLen))
|
c@4
|
630
|
c@4
|
631 for erb in range(39):
|
c@4
|
632
|
c@4
|
633 zArr = input*np.exp(-2*np.pi*1j*f0[erb]*k*T)
|
c@4
|
634 wArr = np.zeros((inLen+1))
|
c@4
|
635
|
c@4
|
636 for i in range(1,inLen+1):
|
c@4
|
637 wArr[i] = wArr[i-1] + (1 - np.exp(-2*np.pi*b[erb]*T))*(zArr[i-1] - wArr[i-1])
|
c@4
|
638
|
c@4
|
639 out[erb] = (wArr[1:]*np.exp(2*np.pi*1j*f0[erb]*k*T)).real
|
c@4
|
640
|
c@4
|
641 return out
|
c@4
|
642
|
c@0
|
643
|
c@0
|
644 def v_Pascal(input, SPL):
|
c@0
|
645 """
|
c@0
|
646 A function to convert a signal, normalised to an amplitude range of -1 to 1, to a signal represented in pressure (units: Pascal).
|
c@0
|
647
|
c@0
|
648 Parameters:
|
c@0
|
649 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required)
|
c@0
|
650 * SPL (type: double) - the sound pressure level (SPL) at 0 dBFS, e.g., the SPL of a sine
|
c@0
|
651 wave with peaks at amplitude 1 and troughs at amplitude -1. (Required)
|
c@0
|
652
|
c@0
|
653 Returns:
|
c@0
|
654 * y (type: numpy array of floats) - array with dimensions equal to the input signal containing the input represented
|
c@0
|
655 as a pressure signal.
|
c@6
|
656
|
c@6
|
657 NOTE If input signal contains one or more zeros, a divide by zero warning will be outputted. This warning can be ignored.
|
c@0
|
658 """
|
c@0
|
659
|
c@0
|
660 input = np.array(input)
|
c@9
|
661 sigRMS = rms(input)
|
c@9
|
662 y = input*0.00002*10**(SPL/20.0)
|
c@0
|
663
|
c@0
|
664 return y
|
c@0
|
665
|
c@9
|
666 def rms(input):
|
c@9
|
667
|
c@9
|
668 sigRMS = np.sqrt(np.mean(input**2))
|
c@9
|
669
|
c@9
|
670 return sigRMS
|
c@9
|
671
|
c@0
|
672 def pa_i(input, C=406):
|
c@0
|
673 """
|
c@0
|
674 A function to convert a pressure signal (unit: Pascal) to an intensity signal.
|
c@0
|
675
|
c@0
|
676 Parameters:
|
c@0
|
677 * input (type: array-like matrix of floats) - pressure signal (unit: Pascal) (Required)
|
c@0
|
678 * C (type: double) - the acoustic impedance of the air (Optional; Default = 406)
|
c@0
|
679
|
c@0
|
680 Returns:
|
c@0
|
681 * y (type: numpy array of floats) - array with dimensions equal to the input signal containing the input represented
|
c@0
|
682 as a pressure signal.
|
c@0
|
683 """
|
c@0
|
684
|
c@0
|
685 input = np.array(input)
|
c@0
|
686 y = (input**2) / C
|
c@0
|
687
|
c@0
|
688 return y
|
c@0
|
689
|
c@0
|
690 def at_normalise(input):
|
c@0
|
691 """
|
c@0
|
692 A function to normalise an intensity signal with the audibility threshold.
|
c@0
|
693
|
c@0
|
694 Parameters:
|
c@0
|
695 * input (type: array-like matrix of floats) - intensity signal (unit: Pascal) (Required)
|
c@0
|
696
|
c@0
|
697 Returns:
|
c@0
|
698 * y (type: numpy array of floats) - array with dimensions equal to the input signal containing the input normalised
|
c@0
|
699 with the audibility threshold.
|
c@0
|
700 """
|
c@0
|
701
|
c@0
|
702 input = np.array(input)
|
c@5
|
703 y = input / (1*(10**-12))
|
c@0
|
704
|
c@1
|
705 return y
|
c@0
|
706
|
c@0
|
707 def downsample(input, factor=100):
|
c@0
|
708 """
|
c@0
|
709 A function to downsample a signal, input, with sampling frequency, fs, by a downsample factor of factor.
|
c@0
|
710
|
c@0
|
711 NOTE: It is advised to use the fir_antialias() function before downsampling to remove any high frequencies
|
c@0
|
712 which would otherwise represented as low frequencies due to aliasing.
|
c@0
|
713
|
c@0
|
714 Parameters:
|
c@0
|
715 * input (type: array-like matrix of floats) - input signal. (Required)
|
c@0
|
716 * factor - downsample factor (Optional; Default = 100)
|
c@0
|
717
|
c@0
|
718 Returns:
|
c@0
|
719 * output (type: numpy array of floats) - array with outer dimensions equivalent to the to the input, and
|
c@0
|
720 inner dimension equal to np.floor(lenIn / factor) where lenIn is the length of the inner dimension.
|
c@0
|
721 """
|
c@0
|
722
|
c@0
|
723 input = np.array(input)
|
c@0
|
724 shapeIn = np.shape(input)
|
c@0
|
725 nDim = np.shape(shapeIn)
|
c@0
|
726 lenIn = shapeIn[nDim[0]-1]
|
c@0
|
727 lenOut = np.floor(lenIn / factor)
|
c@0
|
728 n = np.linspace(0,lenIn,lenOut, endpoint=False).astype(np.int)
|
c@0
|
729 output = input[...,n]
|
c@0
|
730
|
c@0
|
731 return output
|
c@0
|
732
|
c@0
|
733 def half_rectification(input):
|
c@0
|
734 """
|
c@0
|
735 A function which performs a half-wave rectification on the input signal.
|
c@0
|
736
|
c@0
|
737 Parameters:
|
c@0
|
738 * input (type: array-like matrix of floats) - input signal. (Required)
|
c@0
|
739
|
c@0
|
740 Returns:
|
c@0
|
741 * y (type: numpy array of floats) - an array with dimensions of input containing the half-wave rectification of
|
c@0
|
742 input.
|
c@0
|
743 """
|
c@0
|
744
|
c@0
|
745
|
c@0
|
746 y = np.array(input)
|
c@0
|
747 y[y<0] = 0
|
c@0
|
748
|
c@0
|
749 return y
|
c@0
|
750
|
c@9
|
751 def filterbank_decomposition(input, b, a = None, verbose = False):
|
c@0
|
752 """
|
c@4
|
753 A function to run the input through a bandpass filter bank with parameters defined by the b and a coefficints.
|
c@0
|
754
|
c@0
|
755 Parameters:
|
c@0
|
756 * input (type: array-like matrix of floats) - input signal. (Required)
|
c@4
|
757 * b (type: array-like matrix of floats) - the b coefficients of each filter in shape b[numOfFilters][numOfCoeffs]. (Required)
|
c@4
|
758 * a (type: array-like matrix of floats) - the a coefficients of each filter in shape a[numOfFilters][numOfCoeffs].
|
c@4
|
759 If not specified, the filter is treated as a FIR filter. (Optional; Default = 1)
|
c@4
|
760 * verbose (type: boolean) - determines whether to display the current subroutine/progress of the procedure.
|
c@4
|
761 (Optional; Default = False)
|
c@4
|
762
|
c@4
|
763 Returns:
|
c@4
|
764 * y (type: numpy array of floats) - an array with inner dimensions equal to that of the input and outer dimension equal to
|
c@4
|
765 the length of fc (i.e. the number of bandpass filters in the bank) containing the outputs to each filter. The output
|
c@4
|
766 signal of the nth filter can be accessed using y[n].
|
c@4
|
767 """
|
c@4
|
768
|
c@4
|
769 input = np.array(input)
|
c@4
|
770 bShape = np.shape(b)
|
c@4
|
771 nFilters = bShape[0]
|
c@9
|
772 lengthFilter = bShape[1]
|
c@4
|
773
|
c@9
|
774 shape = (nFilters,) + (np.shape(input))
|
c@9
|
775 shape = np.array(shape[0:])
|
c@9
|
776 shape[-1]=shape[-1]+lengthFilter-1
|
c@9
|
777 y = np.zeros((shape))
|
c@4
|
778
|
c@9
|
779 if(verbose): sys.stdout.write("Running filterbank filterbank_decomposition.\n")
|
c@4
|
780 for i in range(nFilters):
|
c@5
|
781 if(verbose):
|
c@5
|
782 sys.stdout.write("\r" + str(int(np.round(100.0*i/nFilters))) + "% complete.")
|
c@5
|
783 sys.stdout.flush()
|
c@8
|
784 x = np.array(input)
|
c@9
|
785 y[i] = sp.fftconvolve(x,b[i])
|
c@6
|
786
|
c@6
|
787 if(verbose): sys.stdout.write("\n")
|
c@6
|
788
|
c@4
|
789 return y
|
c@4
|
790
|
c@4
|
791 def get_Modulation_filter_bank_coefficients(fs, fc, bw, order = 1024, verbose = False):
|
c@4
|
792 """
|
c@4
|
793 A function which returns the b and a coefficients of the modulation filter bank of length equal to the length of fc. Each
|
c@4
|
794 bandpass filter is designed by defining the centre frequencies, fc, and bandwidths, bw.
|
c@4
|
795
|
c@4
|
796 Parameters:
|
c@0
|
797 * fs (type: numerical) - the sampling frequency of the input signal. (Required)
|
c@0
|
798 * fc (type: array-like vector of floats) - the centre off frequencies (unnormalised) of each bandpass filter.
|
c@0
|
799 The length of this vector determines the number of filters in the bank.
|
c@0
|
800 * bw (type: array-like vector of floats) - the bandwidths (unnormalised) of each bandpass filter. Must be equal
|
c@0
|
801 to or more than the length of fc. If the length is more, all elements exceeding the length of fc - 1 will be
|
c@0
|
802 ignored.
|
c@0
|
803 * order (type: numerical int) - the order of the filter (number of taps minus 1) (Optional; Default = 1024)
|
c@0
|
804 * verbose (type: boolean) - determines whether to display the current subroutine/progress of the procedure.
|
c@0
|
805 (Optional; Default = False)
|
c@0
|
806
|
c@0
|
807 Returns:
|
c@4
|
808 * b (type: numpy array of floats) - an array of size order + 1 (i.e. a coefficient for each tap)
|
c@0
|
809 """
|
c@4
|
810
|
c@4
|
811
|
c@0
|
812 nFreqs = len(fc)
|
c@4
|
813
|
c@9
|
814 if(verbose): sys.stdout.write("Running frequency filterbank_decomposition.")
|
c@4
|
815
|
c@0
|
816 for i in range(nFreqs):
|
c@5
|
817 if(verbose):
|
c@5
|
818 sys.stdout.write("\r" + str(int(np.round(100.0*i/nFreqs))) + "% complete.")
|
c@5
|
819 sys.stdout.flush()
|
c@0
|
820 low = fc[i]-bw[i]/2;
|
c@0
|
821 high = fc[i]+bw[i]/2;
|
c@0
|
822 b = fir_bandpass(low, high, fs, order, verbose)
|
c@4
|
823
|
c@4
|
824 return b
|
c@0
|
825
|
c@9
|
826 def temporal_integration(input, fs, type='STL'):
|
c@9
|
827 """
|
c@9
|
828 Convert from instantaneous loudness to STL (type='STL'), or STL to LTL (type='LTL').
|
c@9
|
829
|
c@9
|
830 Parameters:
|
c@9
|
831 * input (type: array-like matrix of floats) - signal. Should be instantaneous loudness if type='STL', or STL if type='LTL' (Required)
|
c@9
|
832 * fs (type: numerical) - sample frequency of the signal, input. (Required)
|
c@9
|
833 * type (type: string) - 'STL' or 'LTL'
|
c@9
|
834
|
c@9
|
835 Returns:
|
c@9
|
836 * Output (type: array-like matrix of floats) - output signal.
|
c@9
|
837 """
|
c@9
|
838 Ti = 1.0/fs
|
c@9
|
839 prevOutput = 0;
|
c@9
|
840 output = np.zeros(np.shape(input))
|
c@9
|
841 if(type=='STL'):
|
c@9
|
842 Ta = 0.0217
|
c@9
|
843 Tr = 0.0495
|
c@9
|
844 elif(type=='LTL'):
|
c@9
|
845 Ta = 0.0995
|
c@9
|
846 Tr = 1.9995
|
c@9
|
847 else:
|
c@9
|
848 str = "Type argument " + type + " is unknown"
|
c@9
|
849 raise ValueError(str)
|
c@9
|
850
|
c@9
|
851 a = 1 - np.exp(-Ti/Ta)
|
c@9
|
852 r = 1 - np.exp(-Ti/Tr)
|
c@9
|
853
|
c@9
|
854 for i in range(len(input)):
|
c@9
|
855 if(input[i] > prevOutput):
|
c@9
|
856 output[i] = a*input[i] + (1-a)*prevOutput
|
c@9
|
857 else:
|
c@9
|
858 output[i] = r*input[i] + (1-r)*prevOutput
|
c@9
|
859 prevOutput = output[i]
|
c@9
|
860
|
c@9
|
861 return output
|
c@9
|
862
|
c@3
|
863 def exp_smoothing(fs, tc = 0.01):
|
c@3
|
864 """
|
c@3
|
865 Designs an exponential filter, y[n] = alpha*x[n] - -(1-alpha)*y[n-1], where alpha = T/(tc+T), where T
|
c@3
|
866 is the inverse of the sampling frequency and time constant, tc, is specified.
|
c@3
|
867
|
c@3
|
868 Parameters:
|
c@3
|
869 * fs (type: numerical) - sampling frequency of the signal to be filtered (Required)
|
c@3
|
870 * tc (type: numerical) - the time constant of the filter. (Optional; Default = 0.01)
|
c@3
|
871
|
c@3
|
872 Returns:
|
c@3
|
873 * b (type: numerical) - the coefficient of x[n]. Equal to alpha.
|
c@3
|
874 * a (type: numpy array of floats) - an array of size 2 of the coefficients of y[n] (a[0] = 1) and y[n-1]
|
c@3
|
875 """
|
c@3
|
876
|
c@3
|
877 T = 1.0/fs
|
c@3
|
878 alpha = T/(tc + T)
|
c@3
|
879 b = [alpha]
|
c@3
|
880 a = [1, -(1-alpha)]
|
c@3
|
881
|
c@3
|
882 return b, a
|
c@3
|
883
|
c@3
|
884 def antialias_fir(fs, fc=100, order=64):
|
c@3
|
885 """
|
c@3
|
886 A function which returns the b coefficients for a lowpass fir filter with specified requirements.
|
c@3
|
887 Made specifically to remove aliasing when downsampling, but can be used for any application that
|
c@3
|
888 requires a lowpass filter.
|
c@3
|
889
|
c@3
|
890 Parameters:
|
c@3
|
891 * fs (type: numerical) - sampling frequency of the signal to be filtered (Required)
|
c@3
|
892 * fc (type: numerical) - unnormalised cut off frequency of the filter (Optional; Default = 100)
|
c@3
|
893 * order (type: numerical int) - the order of the filter (number of taps minus 1) (Optional; Default = 64)
|
c@3
|
894
|
c@3
|
895 Returns:
|
c@3
|
896 * b (type: numpy array of floats) - an array of size order + 1 (i.e. a coefficient for each tap)
|
c@3
|
897 """
|
c@3
|
898
|
c@3
|
899 nyquist = 0.5*fs
|
c@3
|
900 fcNorm = fc/nyquist
|
c@3
|
901 b = sp.firwin(order+1, fcNorm)
|
c@3
|
902
|
c@3
|
903 return b
|
c@3
|
904
|
c@4
|
905 def fir_bandpass(low, high, fs, order = 4096, verbose = False):
|
c@0
|
906 """
|
c@0
|
907 A function which returns the b coefficients for a bandpass fir filter with specified requirements.
|
c@0
|
908
|
c@0
|
909 Parameters:
|
c@0
|
910 * low - the lower cutoff frequency of the filter. (Required)
|
c@0
|
911 * high - the upper cutoff frequency of the filter. (Required)
|
c@0
|
912 * fs (type: numerical) - sampling frequency of the signal to be filtered. (Required)
|
c@0
|
913 * order (type: numerical int) - the order of the filter (number of taps minus 1) (Optional; Default = 1024)
|
c@6
|
914 * verbose (type: boolean) - determines whether to display info on the current subroutine
|
c@0
|
915 of the procedure. (Optional; Default = False)
|
c@0
|
916
|
c@0
|
917 Returns:
|
c@0
|
918 * b (type: numpy array of floats) - an array of size order + 1 (i.e. a coefficient for each tap).
|
c@0
|
919 """
|
c@0
|
920
|
c@0
|
921 nyquist = 0.5*fs
|
c@0
|
922 lowNorm = low/nyquist
|
c@0
|
923 highNorm = high/nyquist
|
c@5
|
924 if(verbose): sys.stdout.write("Low: " + str(lowNorm) + "; High: " + str(highNorm))
|
c@0
|
925 b = sp.firwin(order+1, [lowNorm, highNorm], pass_zero=False)
|
c@0
|
926
|
c@0
|
927 return b |