Mercurial > hg > cm
comparison cortical_model.py @ 4:29cd3e735c4c
* Added run.py for testing
* Changed frequency decomposition to bank of gammatones
author | Carl Bussey <c.bussey@se10.qmul.ac.uk> |
---|---|
date | Sat, 22 Feb 2014 13:53:55 +0000 |
parents | 2d80632482b3 |
children | d7b2784ff5a3 |
comparison
equal
deleted
inserted
replaced
3:2d80632482b3 | 4:29cd3e735c4c |
---|---|
249 """ | 249 """ |
250 | 250 |
251 input = np.array(input) | 251 input = np.array(input) |
252 inputOMFir = outMidFir(input) | 252 inputOMFir = outMidFir(input) |
253 inputPa = v_Pascal(inputOMFir, SPL) | 253 inputPa = v_Pascal(inputOMFir, SPL) |
254 gtfs = gamma_tone_filter(inputPa, fs, verbose = verbose) | 254 b = gamma_tone_filter(fs) |
255 gtfs = decomposition(inputPa, b, verbose = verbose) | |
255 if (rectify): | 256 if (rectify): |
256 gtfs = half_rectification(gtfs) | 257 gtfs = half_rectification(gtfs) |
257 gtfs = pa_i(gtfs) | 258 gtfs = pa_i(gtfs) |
258 gtfs = at_normalise(gtfs) | 259 gtfs = at_normalise(gtfs) |
259 b,a = exp_smoothing(fs) | 260 b,a = exp_smoothing(fs) |
260 gtfs = sp.lfilter(b,a,gtfs) | 261 gtfs = sp.lfilter(b,a,gtfs) |
261 | 262 |
262 return gtfs | 263 return gtfs |
263 | 264 |
264 def plot_excitation_response(input = 0, fs = 44100, outMidFilt = True, xscale = 'log', yscale = 'log'): | 265 def plot_excitation_response(input = None, fs = 44100, outMidFilt = True, gammatone = True, xscale = 'log', yscale = 'log'): |
265 """ | 266 """ |
266 A function that plots the transfer function of the outer middle ear and each gammatone filter. | 267 A function that plots the transfer function of the outer middle ear and each gammatone filter. |
267 | 268 |
268 Parameters: | 269 Parameters: |
269 * fs (type: numerical) - the sampling frequency of the signal. (Optional; Default = 44100) | 270 * fs (type: numerical) - the sampling frequency of the signal. (Optional; Default = 44100) |
270 * outMidFilt (type: boolean) - filter the signal by the outer and middle ear FIR filter. (Optional; Default = True) | 271 * outMidFilt (type: boolean) - filter the signal by the outer and middle ear FIR filter. (Optional; Default = True) |
271 * xscale (type: string) - the scale of the frequency axis. Values are 'log' or 'linear'. (Optional; Default = 'log') | 272 * xscale (type: string) - the scale of the frequency axis. Values are 'log' or 'linear'. (Optional; Default = 'log') |
272 * yscale (type: string) - the scale of the amplitude axis. Values are 'log' or 'linear'. (Optional; Default = 'log') | 273 * yscale (type: string) - the scale of the amplitude axis. Values are 'log' or 'linear'. (Optional; Default = 'log') |
273 | 274 """ |
274 Returns: | 275 |
275 * y (type: numpy array of floats) - array with size ((39,np.ceil(fs))) containing the impulse response of the | 276 if input == None: |
276 signal at each gammatone filter (and optionally, including the outer middle ear response). The response at the | 277 input = np.zeros((np.ceil(fs))) |
277 nth gammatone filter can be accessed by y[n]. | |
278 """ | |
279 | |
280 if ((np.shape(input)==())): | |
281 input = np.zeros(np.ceil(fs)) | |
282 input[0] = 1 | 278 input[0] = 1 |
279 | |
283 if(outMidFilt): input = outMidFir(input) | 280 if(outMidFilt): input = outMidFir(input) |
284 y = gamma_tone_filter(input, fs) | 281 if(gammatone): |
285 | 282 b = gamma_tone_filter(fs) |
286 for i in range(np.shape(y)[0]): | 283 input = decomposition(input, b) |
287 utils.plot_fft(y[i],xscale, yscale, False) | 284 #input = holdsworthGamma(input,fs) |
285 numPlot = range(np.shape(input)[0]) | |
286 else: | |
287 numPlot = (0,) | |
288 input = input.reshape(1,len(input)) | |
289 | |
290 for i in numPlot: | |
291 utils.plot_fft(input[i],xscale, yscale, False) | |
288 | 292 |
289 plt.show() | 293 plt.show() |
290 | 294 |
291 return fft.fft(y) | 295 return |
292 | 296 |
293 def get_modulation_i(input, fs): | 297 def get_modulation_i(input, fs): |
294 """ | 298 """ |
295 A function to calculate the modulation intensity of the input intensity signal. The function implements a | 299 A function to calculate the modulation intensity of the input intensity signal. The function implements a |
296 filter bank of bandpass filters with cut off frequencies ranging from 0.25 to 16 Hz. | 300 filter bank of bandpass filters with cut off frequencies ranging from 0.25 to 16 Hz. |
332 b = utils.load_outMidFir_coeff() | 336 b = utils.load_outMidFir_coeff() |
333 y = sp.lfilter(b, (1), input) | 337 y = sp.lfilter(b, (1), input) |
334 | 338 |
335 return y | 339 return y |
336 | 340 |
337 def gamma_tone_filter(input, fs, verbose = False): | 341 def gamma_tone_filter(fs): |
338 """ | 342 """ |
339 A function to filter to decompose the input signal into 39 different gammatones filtered signals modelling the ERBs. | 343 A function to filter to decompose the input signal into 39 different gammatones filtered signals modelling the ERBs. |
340 | 344 |
341 Parameters: | 345 Parameters: |
342 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required) | 346 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required) |
345 Returns: | 349 Returns: |
346 * y (type: numpy array of floats) - array with size ((39),np.shape(input)) containing the impulse response of the | 350 * y (type: numpy array of floats) - array with size ((39),np.shape(input)) containing the impulse response of the |
347 signal at each gammatone filter. The response at the nth gammatone filter can be accessed by y[n]. | 351 signal at each gammatone filter. The response at the nth gammatone filter can be accessed by y[n]. |
348 """ | 352 """ |
349 | 353 |
350 input = np.array(input) | 354 nerbs = 39 |
351 fc, bw = utils.load_erb_data() | 355 erbs = np.array(range(1,nerbs+1)) |
352 y = decomposition(input,fs,fc,bw, verbose = verbose) | 356 fc = (10**(erbs/21.366)-1)/0.004368 |
353 | 357 bw = 24.673 * (1 + 0.004368*fc) |
354 return y | 358 N = 4 |
359 filterLength = 4096 | |
360 t = 1.0*np.array(range(filterLength))/fs | |
361 | |
362 gain=((1.019*bw*(2.0*np.pi)/float(fs))**4)/6.0 | |
363 | |
364 PI = N * np.arctan(1) | |
365 | |
366 b = np.zeros((nerbs,filterLength)) | |
367 | |
368 for i in range(39): | |
369 b[i] = gain[i] * t**(N-1) * fs**(N-1) * np.exp(-2*np.pi*bw[i]*t) * np.cos(2*np.pi*fc[i]*t) | |
370 | |
371 return b | |
372 | |
373 def holdsworthGamma(input, fs): | |
374 """ | |
375 | |
376 """ | |
377 input = np.array(input) | |
378 input = input + 0j | |
379 | |
380 T = 1.0/fs | |
381 | |
382 ERBs = np.array(range(1,40)) | |
383 f0 = (10**(ERBs/21.4)-1)/4.37e-3 | |
384 | |
385 inLen = len(input) | |
386 b = 24.673 * (1 + 0.004368*f0) | |
387 k = np.array(range(inLen)) + 0j | |
388 out = np.zeros((39,inLen)) | |
389 | |
390 for erb in range(39): | |
391 | |
392 zArr = input*np.exp(-2*np.pi*1j*f0[erb]*k*T) | |
393 wArr = np.zeros((inLen+1)) | |
394 | |
395 for i in range(1,inLen+1): | |
396 wArr[i] = wArr[i-1] + (1 - np.exp(-2*np.pi*b[erb]*T))*(zArr[i-1] - wArr[i-1]) | |
397 | |
398 out[erb] = (wArr[1:]*np.exp(2*np.pi*1j*f0[erb]*k*T)).real | |
399 | |
400 return out | |
401 | |
355 | 402 |
356 def v_Pascal(input, SPL): | 403 def v_Pascal(input, SPL): |
357 """ | 404 """ |
358 A function to convert a signal, normalised to an amplitude range of -1 to 1, to a signal represented in pressure (units: Pascal). | 405 A function to convert a signal, normalised to an amplitude range of -1 to 1, to a signal represented in pressure (units: Pascal). |
359 | 406 |
449 y = np.array(input) | 496 y = np.array(input) |
450 y[y<0] = 0 | 497 y[y<0] = 0 |
451 | 498 |
452 return y | 499 return y |
453 | 500 |
454 def decomposition(input, fs, fc, bw, order=1024, verbose = False): | 501 def decomposition(input, b, a = None, verbose = False): |
455 """ | 502 """ |
456 A function to run the input filter through a bandpass filter bank of length equal to the length of fc. Each | 503 A function to run the input through a bandpass filter bank with parameters defined by the b and a coefficints. |
504 | |
505 Parameters: | |
506 * input (type: array-like matrix of floats) - input signal. (Required) | |
507 * b (type: array-like matrix of floats) - the b coefficients of each filter in shape b[numOfFilters][numOfCoeffs]. (Required) | |
508 * a (type: array-like matrix of floats) - the a coefficients of each filter in shape a[numOfFilters][numOfCoeffs]. | |
509 If not specified, the filter is treated as a FIR filter. (Optional; Default = 1) | |
510 * verbose (type: boolean) - determines whether to display the current subroutine/progress of the procedure. | |
511 (Optional; Default = False) | |
512 | |
513 Returns: | |
514 * y (type: numpy array of floats) - an array with inner dimensions equal to that of the input and outer dimension equal to | |
515 the length of fc (i.e. the number of bandpass filters in the bank) containing the outputs to each filter. The output | |
516 signal of the nth filter can be accessed using y[n]. | |
517 """ | |
518 | |
519 input = np.array(input) | |
520 bShape = np.shape(b) | |
521 nFilters = bShape[0] | |
522 | |
523 if a == None: | |
524 a = np.ones(nFilters) | |
525 | |
526 shape = (nFilters,) + np.shape(input) | |
527 shape = shape[0:] | |
528 y = np.zeros(shape) | |
529 | |
530 if(verbose): print "Running decomposition." | |
531 for i in range(nFilters): | |
532 if(verbose): print str(100.0*i/nFilters) + "% complete." | |
533 x = deepcopy(input) | |
534 y[i] = sp.lfilter(b[i],a[i],x) | |
535 | |
536 return y | |
537 | |
538 def get_Modulation_filter_bank_coefficients(fs, fc, bw, order = 1024, verbose = False): | |
539 """ | |
540 A function which returns the b and a coefficients of the modulation filter bank of length equal to the length of fc. Each | |
457 bandpass filter is designed by defining the centre frequencies, fc, and bandwidths, bw. | 541 bandpass filter is designed by defining the centre frequencies, fc, and bandwidths, bw. |
458 | 542 |
459 Parameters: | 543 Parameters: |
460 * input (type: array-like matrix of floats) - input signal. (Required) | |
461 * fs (type: numerical) - the sampling frequency of the input signal. (Required) | 544 * fs (type: numerical) - the sampling frequency of the input signal. (Required) |
462 * fc (type: array-like vector of floats) - the centre off frequencies (unnormalised) of each bandpass filter. | 545 * fc (type: array-like vector of floats) - the centre off frequencies (unnormalised) of each bandpass filter. |
463 The length of this vector determines the number of filters in the bank. | 546 The length of this vector determines the number of filters in the bank. |
464 * bw (type: array-like vector of floats) - the bandwidths (unnormalised) of each bandpass filter. Must be equal | 547 * bw (type: array-like vector of floats) - the bandwidths (unnormalised) of each bandpass filter. Must be equal |
465 to or more than the length of fc. If the length is more, all elements exceeding the length of fc - 1 will be | 548 to or more than the length of fc. If the length is more, all elements exceeding the length of fc - 1 will be |
467 * order (type: numerical int) - the order of the filter (number of taps minus 1) (Optional; Default = 1024) | 550 * order (type: numerical int) - the order of the filter (number of taps minus 1) (Optional; Default = 1024) |
468 * verbose (type: boolean) - determines whether to display the current subroutine/progress of the procedure. | 551 * verbose (type: boolean) - determines whether to display the current subroutine/progress of the procedure. |
469 (Optional; Default = False) | 552 (Optional; Default = False) |
470 | 553 |
471 Returns: | 554 Returns: |
472 * y (type: numpy array of floats) - an array with inner dimensions equal to that of the input and outer dimension equal to | 555 * b (type: numpy array of floats) - an array of size order + 1 (i.e. a coefficient for each tap) |
473 the length of fc (i.e. the number of bandpass filters in the bank) containing the outputs to each filter. The output | 556 """ |
474 signal of the nth filter can be accessed using y[n]. | 557 |
475 """ | 558 |
476 | |
477 input = np.array(input) | |
478 nFreqs = len(fc) | 559 nFreqs = len(fc) |
479 shape = (nFreqs,) + np.shape(input) | 560 |
480 shape = shape[0:] | |
481 y = np.zeros(shape) | |
482 | |
483 if(verbose): print "Running frequency decomposition." | 561 if(verbose): print "Running frequency decomposition." |
562 | |
484 for i in range(nFreqs): | 563 for i in range(nFreqs): |
485 if(verbose): print str(100.0*i/nFreqs) + "% complete." | 564 if(verbose): print str(100.0*i/nFreqs) + "% complete." |
486 low = fc[i]-bw[i]/2; | 565 low = fc[i]-bw[i]/2; |
487 high = fc[i]+bw[i]/2; | 566 high = fc[i]+bw[i]/2; |
488 if(verbose): print "Low: " + str(low) + "; High: " + str(high) | 567 if(verbose): print "Low: " + str(low) + "; High: " + str(high) |
489 b = fir_bandpass(low, high, fs, order, verbose) | 568 b = fir_bandpass(low, high, fs, order, verbose) |
490 x = deepcopy(input) | 569 |
491 y[i] = sp.lfilter(b,(1),x) | 570 return b |
492 | |
493 return y | |
494 | 571 |
495 def exp_smoothing(fs, tc = 0.01): | 572 def exp_smoothing(fs, tc = 0.01): |
496 """ | 573 """ |
497 Designs an exponential filter, y[n] = alpha*x[n] - -(1-alpha)*y[n-1], where alpha = T/(tc+T), where T | 574 Designs an exponential filter, y[n] = alpha*x[n] - -(1-alpha)*y[n-1], where alpha = T/(tc+T), where T |
498 is the inverse of the sampling frequency and time constant, tc, is specified. | 575 is the inverse of the sampling frequency and time constant, tc, is specified. |
532 fcNorm = fc/nyquist | 609 fcNorm = fc/nyquist |
533 b = sp.firwin(order+1, fcNorm) | 610 b = sp.firwin(order+1, fcNorm) |
534 | 611 |
535 return b | 612 return b |
536 | 613 |
537 def fir_bandpass(low, high, fs, order = 1024, verbose = False): | 614 def fir_bandpass(low, high, fs, order = 4096, verbose = False): |
538 """ | 615 """ |
539 A function which returns the b coefficients for a bandpass fir filter with specified requirements. | 616 A function which returns the b coefficients for a bandpass fir filter with specified requirements. |
540 | 617 |
541 Parameters: | 618 Parameters: |
542 * low - the lower cutoff frequency of the filter. (Required) | 619 * low - the lower cutoff frequency of the filter. (Required) |