comparison cortical_model.py @ 0:5609fd93e935

First commit.
author Carl Bussey <c.bussey@se10.qmul.ac.uk>
date Sat, 25 Jan 2014 20:00:38 +0000
parents
children dc43033a2c20
comparison
equal deleted inserted replaced
-1:000000000000 0:5609fd93e935
1 """
2 A module used for auditory analysis.
3
4 Models currently implemented:
5 * Frequency-modulation analysis model based on the human auditory system.
6
7 Model implementations in progress:
8 * Glasberg and Moore model
9
10 Packaged dependencies:
11 * utils.py and/or utils.pyc
12 * erb.dat
13 * outMidFir.dat
14
15 External dependencies:
16 * scipy
17 * numpy
18 * copy
19 * matplotlib
20 """
21
22 import utils
23 import scipy.signal as sp
24 import numpy as np
25 from copy import deepcopy
26 import matplotlib.pyplot as plt
27
28 def get_partial_loudness():
29 """
30 A function to calculate the partial loudness of an excitation pattern at given ERB.
31
32 TO DO
33 """
34
35
36 return
37
38 def get_excitation_i(input, fs, SPL, rectify=False):
39 """
40 A function to calculate the excitation intensity of the input signal.
41
42 Parameters:
43 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required)
44 * fs (type: numerical) - sample frequency of the signal, input. (Required)
45 * SPL (type: double) - the sound pressure level (SPL) at 0 dBFS, e.g., the SPL of a sine
46 wave with peaks at amplitude 1 and troughs at amplitude -1. (Required)
47 * rectify (type: boolean) - Specifies whether to include half wave rectification, modelling the direction
48 of that the cochlear nerves vibrate.
49 True to include, False to ignore. (Optional; Default = False)
50
51 Returns:
52 * gtfs (type: numpy array of floats) - array with size ((39,) + np.shape(input)) containing the excitation
53 pattern (in sound intensity) for each ERB of input signal. The excitation pattern for the nth ERB can
54 be accessed with gtfs[n].
55 """
56
57 input = np.array(input)
58 inputOMFir = outMidFir(input)
59 inputPa = v_Pascal(inputOMFir, SPL)
60 gtfs = gamma_tone_filter(inputPa, fs)
61 if (rectify):
62 gtfs = half_rectification(gtfs)
63 gtfs = pa_i(gtfs)
64 gtfs = at_normalise(gtfs)
65
66 return gtfs
67
68 def plot_excitation_tf(fs = 44100, outMidFilt = True, xscale = 'log', yscale = 'log'):
69 """
70 A function that plots the transfer function of the outer middle ear and each gammatone filter.
71
72 Parameters:
73 * fs (type: numerical) - the sampling frequency of the signal. (Optional; Default = 44100)
74 * outMidFilt (type: boolean) - filter the signal by the outer and middle ear FIR filter. (Optional; Default = True)
75 * xscale (type: string) - the scale of the frequency axis. Values are 'log' or 'linear'. (Optional; Default = 'log')
76 * yscale (type: string) - the scale of the amplitude axis. Values are 'log' or 'linear'. (Optional; Default = 'log')
77
78 Returns:
79 * y (type: numpy array of floats) - array with size ((39,np.ceil(fs))) containing the impulse response of the
80 signal at each gammatone filter (and optionally, including the outer middle ear response). The response at the
81 nth gammatone filter can be accessed by y[n].
82 """
83
84 input = np.zeros(np.ceil(fs))
85 input[0] = 1
86 if(outMidFilt): input = outMidFir(input)
87 y = gamma_tone_filter(input, fs)
88
89 for i in range(np.shape(y)[0]):
90 utils.plot_fft(y[i],xscale, yscale, False)
91
92 plt.show()
93
94 return y
95
96 def get_modulation_i(input, fs):
97 """
98 A function to calculate the modulation intensity of the input intensity signal. The function implements a
99 filter bank of bandpass filters with cut off frequencies ranging from 0.25 to 16 Hz.
100
101 Parameters:
102 * input (type: array-like matrix of floats) - the input intensity signal.
103 E.g., use get_excitation_i() to obtain excitation intensity and use as input.
104 * fs (type: numerical) - sampling frequency of input signal
105
106 Returns:
107 * y (type: numpy array of floats) - array with size ((10,) + np.shape(input)) containing the
108 modulation intensity of the signal at each modulation filter. The modulation intensity for the nth filter can
109 be accessed with y[n].
110 """
111
112
113 input = np.array(input)
114 b = fir_antialias(fs)
115 input_lp = sp.lfilter(b,(1),input_fr)
116 input_ds = downsample(input_lp, fs)
117 fc = np.array(utils.exp_sequence(-2,4,10))
118 bw = fc/2
119 y = decomposition(input_ds, fs, fc, bw)
120
121 return y
122
123 def outMidFir(input):
124 """
125 A function to filter the input signal with the response of the outer and middle ear.
126
127 Parameters:
128 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required)
129
130 Returns:
131 * y (type: numpy array of floats) - array with dimensions equal to the input signal filtered by the response of
132 the outer and middle ear.
133 """
134
135 input = np.array(input)
136 b = utils.load_outMidFir_coeff()
137 y = sp.lfilter(b, (1), input)
138
139 return y
140
141 def gamma_tone_filter(input, fs):
142 """
143 A function to filter to decompose the input signal into 39 different gammatones filtered signals modelling the ERBs.
144
145 Parameters:
146 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required)
147 * fs (type: numerical) - sample frequency of the signal, input. (Required)
148
149 Returns:
150 * y (type: numpy array of floats) - array with size ((39),np.shape(input)) containing the impulse response of the
151 signal at each gammatone filter. The response at the nth gammatone filter can be accessed by y[n].
152 """
153
154 input = np.array(input)
155 fc, bw = utils.load_erb_data()
156 y = decomposition(input,fs,fc,bw)
157
158 return y
159
160 def v_Pascal(input, SPL):
161 """
162 A function to convert a signal, normalised to an amplitude range of -1 to 1, to a signal represented in pressure (units: Pascal).
163
164 Parameters:
165 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required)
166 * SPL (type: double) - the sound pressure level (SPL) at 0 dBFS, e.g., the SPL of a sine
167 wave with peaks at amplitude 1 and troughs at amplitude -1. (Required)
168
169 Returns:
170 * y (type: numpy array of floats) - array with dimensions equal to the input signal containing the input represented
171 as a pressure signal.
172 """
173
174 input = np.array(input)
175 y = np.sign(input)*(0.00002*10**(np.log10(np.abs(input))+dBFS/20))
176
177 return y
178
179 def pa_i(input, C=406):
180 """
181 A function to convert a pressure signal (unit: Pascal) to an intensity signal.
182
183 Parameters:
184 * input (type: array-like matrix of floats) - pressure signal (unit: Pascal) (Required)
185 * C (type: double) - the acoustic impedance of the air (Optional; Default = 406)
186
187 Returns:
188 * y (type: numpy array of floats) - array with dimensions equal to the input signal containing the input represented
189 as a pressure signal.
190 """
191
192 input = np.array(input)
193 y = (input**2) / C
194
195 return y
196
197 def at_normalise(input):
198 """
199 A function to normalise an intensity signal with the audibility threshold.
200
201 Parameters:
202 * input (type: array-like matrix of floats) - intensity signal (unit: Pascal) (Required)
203
204 Returns:
205 * y (type: numpy array of floats) - array with dimensions equal to the input signal containing the input normalised
206 with the audibility threshold.
207 """
208
209 input = np.array(input)
210 y = input / 1*(10**12)
211
212 return
213
214 def downsample(input, factor=100):
215 """
216 A function to downsample a signal, input, with sampling frequency, fs, by a downsample factor of factor.
217
218 NOTE: It is advised to use the fir_antialias() function before downsampling to remove any high frequencies
219 which would otherwise represented as low frequencies due to aliasing.
220
221 Parameters:
222 * input (type: array-like matrix of floats) - input signal. (Required)
223 * factor - downsample factor (Optional; Default = 100)
224
225 Returns:
226 * output (type: numpy array of floats) - array with outer dimensions equivalent to the to the input, and
227 inner dimension equal to np.floor(lenIn / factor) where lenIn is the length of the inner dimension.
228 """
229
230 input = np.array(input)
231 shapeIn = np.shape(input)
232 nDim = np.shape(shapeIn)
233 lenIn = shapeIn[nDim[0]-1]
234 lenOut = np.floor(lenIn / factor)
235 n = np.linspace(0,lenIn,lenOut, endpoint=False).astype(np.int)
236 output = input[...,n]
237
238 return output
239
240 def antialias_fir(fs, fc=100, order=64):
241 """
242 A function which returns the b coefficients for a lowpass fir filter with specified requirements.
243 Made specifically to remove aliasing when downsampling, but can be used for any application that
244 requires a lowpass filter.
245
246 Parameters:
247 * fs (type: numerical) - sampling frequency of the signal to be filtered (Required)
248 * fc (type: numerical) - unnormalised cut off frequency of the filter (Optional; Default = 100)
249 * order (type: numerical int) - the order of the filter (number of taps minus 1) (Optional; Default = 64)
250
251 Returns:
252 * b (type: numpy array of floats) - an array of size order + 1 (i.e. a coefficient for each tap)
253 """
254
255 nyquist = 0.5*fs
256 fcNorm = fc/nyquist
257 b = sp.firwin(order+1, fcNorm)
258
259 return b
260
261 def half_rectification(input):
262 """
263 A function which performs a half-wave rectification on the input signal.
264
265 Parameters:
266 * input (type: array-like matrix of floats) - input signal. (Required)
267
268 Returns:
269 * y (type: numpy array of floats) - an array with dimensions of input containing the half-wave rectification of
270 input.
271 """
272
273
274 y = np.array(input)
275 y[y<0] = 0
276
277 return y
278
279 def decomposition(input, fs, fc, bw, order=1024, verbose = False):
280 """
281 A function to run the input filter through a bandpass filter bank of length equal to the length of fc. Each
282 bandpass filter is designed by defining the centre frequencies, fc, and bandwidths, bw.
283
284 Parameters:
285 * input (type: array-like matrix of floats) - input signal. (Required)
286 * fs (type: numerical) - the sampling frequency of the input signal. (Required)
287 * fc (type: array-like vector of floats) - the centre off frequencies (unnormalised) of each bandpass filter.
288 The length of this vector determines the number of filters in the bank.
289 * bw (type: array-like vector of floats) - the bandwidths (unnormalised) of each bandpass filter. Must be equal
290 to or more than the length of fc. If the length is more, all elements exceeding the length of fc - 1 will be
291 ignored.
292 * order (type: numerical int) - the order of the filter (number of taps minus 1) (Optional; Default = 1024)
293 * verbose (type: boolean) - determines whether to display the current subroutine/progress of the procedure.
294 (Optional; Default = False)
295
296 Returns:
297 * y (type: numpy array of floats) - an array with inner dimensions equal to that of the input and outer dimension equal to
298 the length of fc (i.e. the number of bandpass filters in the bank) containing the outputs to each filter. The output
299 signal of the nth filter can be accessed using y[n].
300 """
301
302
303 input = np.array(input)
304 nFreqs = len(fc)
305 shape = (nFreqs,) + np.shape(input)
306 shape = shape[0:]
307 y = np.zeros(shape)
308
309 if(verbose): print "Running frequency decomposition."
310 for i in range(nFreqs):
311 if(verbose): print str(100.0*i/nFreqs) + "% complete."
312 low = fc[i]-bw[i]/2;
313 high = fc[i]+bw[i]/2;
314 if(verbose): print "Low: " + str(low) + "; High: " + str(high)
315 b = fir_bandpass(low, high, fs, order, verbose)
316 x = deepcopy(input)
317 y[i] = sp.lfilter(b,(1),x)
318
319 return y
320
321 def fir_bandpass(low, high, fs, order = 1024, verbose = False):
322 """
323 A function which returns the b coefficients for a bandpass fir filter with specified requirements.
324
325 Parameters:
326 * low - the lower cutoff frequency of the filter. (Required)
327 * high - the upper cutoff frequency of the filter. (Required)
328 * fs (type: numerical) - sampling frequency of the signal to be filtered. (Required)
329 * order (type: numerical int) - the order of the filter (number of taps minus 1) (Optional; Default = 1024)
330 * verbose (type: boolean) - determines whether to display the current progress (or info on the current subroutine)
331 of the procedure. (Optional; Default = False)
332
333 Returns:
334 * b (type: numpy array of floats) - an array of size order + 1 (i.e. a coefficient for each tap).
335 """
336
337 nyquist = 0.5*fs
338 lowNorm = low/nyquist
339 highNorm = high/nyquist
340 if(verbose): print "Low: " + str(lowNorm) + "; High: " + str(highNorm)
341 b = sp.firwin(order+1, [lowNorm, highNorm], pass_zero=False)
342
343 return b