Mercurial > hg > cm
changeset 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 |
files | cortical_model.py run.py utils.py |
diffstat | 3 files changed, 135 insertions(+), 38 deletions(-) [+] |
line wrap: on
line diff
--- a/cortical_model.py Tue Feb 04 14:46:06 2014 +0000 +++ b/cortical_model.py Sat Feb 22 13:53:55 2014 +0000 @@ -251,7 +251,8 @@ input = np.array(input) inputOMFir = outMidFir(input) inputPa = v_Pascal(inputOMFir, SPL) - gtfs = gamma_tone_filter(inputPa, fs, verbose = verbose) + b = gamma_tone_filter(fs) + gtfs = decomposition(inputPa, b, verbose = verbose) if (rectify): gtfs = half_rectification(gtfs) gtfs = pa_i(gtfs) @@ -261,7 +262,7 @@ return gtfs -def plot_excitation_response(input = 0, fs = 44100, outMidFilt = True, xscale = 'log', yscale = 'log'): +def plot_excitation_response(input = None, fs = 44100, outMidFilt = True, gammatone = True, xscale = 'log', yscale = 'log'): """ A function that plots the transfer function of the outer middle ear and each gammatone filter. @@ -270,25 +271,28 @@ * outMidFilt (type: boolean) - filter the signal by the outer and middle ear FIR filter. (Optional; Default = True) * xscale (type: string) - the scale of the frequency axis. Values are 'log' or 'linear'. (Optional; Default = 'log') * yscale (type: string) - the scale of the amplitude axis. Values are 'log' or 'linear'. (Optional; Default = 'log') - - Returns: - * y (type: numpy array of floats) - array with size ((39,np.ceil(fs))) containing the impulse response of the - signal at each gammatone filter (and optionally, including the outer middle ear response). The response at the - nth gammatone filter can be accessed by y[n]. """ - if ((np.shape(input)==())): - input = np.zeros(np.ceil(fs)) + if input == None: + input = np.zeros((np.ceil(fs))) input[0] = 1 + if(outMidFilt): input = outMidFir(input) - y = gamma_tone_filter(input, fs) - - for i in range(np.shape(y)[0]): - utils.plot_fft(y[i],xscale, yscale, False) + if(gammatone): + b = gamma_tone_filter(fs) + input = decomposition(input, b) + #input = holdsworthGamma(input,fs) + numPlot = range(np.shape(input)[0]) + else: + numPlot = (0,) + input = input.reshape(1,len(input)) + + for i in numPlot: + utils.plot_fft(input[i],xscale, yscale, False) plt.show() - return fft.fft(y) + return def get_modulation_i(input, fs): """ @@ -334,7 +338,7 @@ return y -def gamma_tone_filter(input, fs, verbose = False): +def gamma_tone_filter(fs): """ A function to filter to decompose the input signal into 39 different gammatones filtered signals modelling the ERBs. @@ -347,11 +351,54 @@ signal at each gammatone filter. The response at the nth gammatone filter can be accessed by y[n]. """ + nerbs = 39 + erbs = np.array(range(1,nerbs+1)) + fc = (10**(erbs/21.366)-1)/0.004368 + bw = 24.673 * (1 + 0.004368*fc) + N = 4 + filterLength = 4096 + t = 1.0*np.array(range(filterLength))/fs + + gain=((1.019*bw*(2.0*np.pi)/float(fs))**4)/6.0 + + PI = N * np.arctan(1) + + b = np.zeros((nerbs,filterLength)) + + for i in range(39): + 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) + + return b + +def holdsworthGamma(input, fs): + """ + + """ input = np.array(input) - fc, bw = utils.load_erb_data() - y = decomposition(input,fs,fc,bw, verbose = verbose) - - return y + input = input + 0j + + T = 1.0/fs + + ERBs = np.array(range(1,40)) + f0 = (10**(ERBs/21.4)-1)/4.37e-3 + + inLen = len(input) + b = 24.673 * (1 + 0.004368*f0) + k = np.array(range(inLen)) + 0j + out = np.zeros((39,inLen)) + + for erb in range(39): + + zArr = input*np.exp(-2*np.pi*1j*f0[erb]*k*T) + wArr = np.zeros((inLen+1)) + + for i in range(1,inLen+1): + wArr[i] = wArr[i-1] + (1 - np.exp(-2*np.pi*b[erb]*T))*(zArr[i-1] - wArr[i-1]) + + out[erb] = (wArr[1:]*np.exp(2*np.pi*1j*f0[erb]*k*T)).real + + return out + def v_Pascal(input, SPL): """ @@ -451,13 +498,49 @@ return y -def decomposition(input, fs, fc, bw, order=1024, verbose = False): +def decomposition(input, b, a = None, verbose = False): """ - A function to run the input filter through a bandpass filter bank of length equal to the length of fc. Each - bandpass filter is designed by defining the centre frequencies, fc, and bandwidths, bw. + A function to run the input through a bandpass filter bank with parameters defined by the b and a coefficints. Parameters: * input (type: array-like matrix of floats) - input signal. (Required) + * b (type: array-like matrix of floats) - the b coefficients of each filter in shape b[numOfFilters][numOfCoeffs]. (Required) + * a (type: array-like matrix of floats) - the a coefficients of each filter in shape a[numOfFilters][numOfCoeffs]. + If not specified, the filter is treated as a FIR filter. (Optional; Default = 1) + * verbose (type: boolean) - determines whether to display the current subroutine/progress of the procedure. + (Optional; Default = False) + + Returns: + * y (type: numpy array of floats) - an array with inner dimensions equal to that of the input and outer dimension equal to + the length of fc (i.e. the number of bandpass filters in the bank) containing the outputs to each filter. The output + signal of the nth filter can be accessed using y[n]. + """ + + input = np.array(input) + bShape = np.shape(b) + nFilters = bShape[0] + + if a == None: + a = np.ones(nFilters) + + shape = (nFilters,) + np.shape(input) + shape = shape[0:] + y = np.zeros(shape) + + if(verbose): print "Running decomposition." + for i in range(nFilters): + if(verbose): print str(100.0*i/nFilters) + "% complete." + x = deepcopy(input) + y[i] = sp.lfilter(b[i],a[i],x) + + return y + +def get_Modulation_filter_bank_coefficients(fs, fc, bw, order = 1024, verbose = False): + """ + A function which returns the b and a coefficients of the modulation filter bank of length equal to the length of fc. Each + bandpass filter is designed by defining the centre frequencies, fc, and bandwidths, bw. + + Parameters: * fs (type: numerical) - the sampling frequency of the input signal. (Required) * fc (type: array-like vector of floats) - the centre off frequencies (unnormalised) of each bandpass filter. The length of this vector determines the number of filters in the bank. @@ -469,28 +552,22 @@ (Optional; Default = False) Returns: - * y (type: numpy array of floats) - an array with inner dimensions equal to that of the input and outer dimension equal to - the length of fc (i.e. the number of bandpass filters in the bank) containing the outputs to each filter. The output - signal of the nth filter can be accessed using y[n]. + * b (type: numpy array of floats) - an array of size order + 1 (i.e. a coefficient for each tap) """ - - input = np.array(input) + + nFreqs = len(fc) - shape = (nFreqs,) + np.shape(input) - shape = shape[0:] - y = np.zeros(shape) - + if(verbose): print "Running frequency decomposition." + for i in range(nFreqs): if(verbose): print str(100.0*i/nFreqs) + "% complete." low = fc[i]-bw[i]/2; high = fc[i]+bw[i]/2; if(verbose): print "Low: " + str(low) + "; High: " + str(high) b = fir_bandpass(low, high, fs, order, verbose) - x = deepcopy(input) - y[i] = sp.lfilter(b,(1),x) - - return y + + return b def exp_smoothing(fs, tc = 0.01): """ @@ -534,7 +611,7 @@ return b -def fir_bandpass(low, high, fs, order = 1024, verbose = False): +def fir_bandpass(low, high, fs, order = 4096, verbose = False): """ A function which returns the b coefficients for a bandpass fir filter with specified requirements.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/run.py Sat Feb 22 13:53:55 2014 +0000 @@ -0,0 +1,20 @@ +import cortical_model as cm +import numpy as np +import utils + +t = np.array(range(44100)) +sine = np.sin(2*np.pi*t*1000/44100) +sine1 = np.sin(2*np.pi*t*100/44100) +x = np.append(sine, sine1) + +exc_i = cm.get_excitation_i(x, 44100, 90, verbose = True) +sl = cm.get_specific_loudness(exc_i) + +for i in range(39): + print "ERB " + str(i) + utils.plot_waveform(sl[i]) + +print "Loudness" +loudness = np.sum(sl,0) + +utils.plot_waveform(loudness) \ No newline at end of file
--- a/utils.py Tue Feb 04 14:46:06 2014 +0000 +++ b/utils.py Sat Feb 22 13:53:55 2014 +0000 @@ -233,8 +233,8 @@ NONE """ - if(xscale.lower() == "log"): plt.gca().set_xscale('log') - if(yscale.lower() == "log"): plt.gca().set_yscale('log') + plt.gca().set_xscale(xscale) + plt.gca().set_yscale(yscale) x = np.array(x) fftx = np.absolute(fft.fft(x))