Mercurial > hg > cm
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 |