annotate 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
rev   line source
c@0 1 """
c@0 2 A module used for auditory analysis.
c@0 3
c@0 4 Models currently implemented:
c@0 5 * Frequency-modulation analysis model based on the human auditory system.
c@0 6
c@0 7 Model implementations in progress:
c@0 8 * Glasberg and Moore model
c@0 9
c@0 10 Packaged dependencies:
c@0 11 * utils.py and/or utils.pyc
c@0 12 * erb.dat
c@0 13 * outMidFir.dat
c@1 14 * tq.dat
c@0 15
c@0 16 External dependencies:
c@0 17 * scipy
c@0 18 * numpy
c@0 19 * copy
c@0 20 * matplotlib
c@0 21 """
c@0 22
c@0 23 import utils
c@0 24 import scipy.signal as sp
c@1 25 import scipy.fftpack as fft
c@0 26 import numpy as np
c@0 27 from copy import deepcopy
c@0 28 import matplotlib.pyplot as plt
c@0 29
c@1 30 def get_specific_loudness(exc_i, inc_loud_region = False):
c@0 31 """
c@3 32 A function to calculate the specific loudness of the excitation patterns at each ERB. Specific loudness is calculated for three regions of
c@3 33 signal intensity, low level, mid level and high level. The high level processing is optional, and by default, ignored. When ignored the high level
c@3 34 region is processed equivalent to that of the mid region.
c@3 35
c@3 36 Parameters:
c@3 37 * 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
c@3 38 ERB channel. (Required)
c@3 39 * inc_loud_region (type: boolean) - Specifies whether to process the high levels differently to the mid levels. (Optional; Default = False)
c@0 40
c@0 41 TO DO
c@0 42 """
c@3 43 exc_i = np.array(exc_i)
c@3 44
c@1 45 lenSig = np.shape(exc_i)[-1] #length signal
c@3 46 tq, G, A, alpha = get_specific_loudness_parameters(lenSig)
c@1 47 specific_loudness = exc_low = exc_mid = exc_high = np.zeros(np.shape(exc_i))
c@0 48
c@1 49 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 50 greater_than_tq = ~less_than_tq #boolean array of elements greater than the threshold of quiet
c@1 51 greater_than_tl = get_greater_than_tl(exc_i) #boolean array of elements greater than the loud threshold
c@1 52 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 53
c@1 54 exc_low = exc_i[less_than_tq]
c@1 55 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 56
c@1 57 if(inc_loud_region):
c@1 58 exc_mid = exc_i[gttq_lttl]
c@1 59 exc_high = exc_i[greater_than_tl]
c@1 60 specific_loudness[gttq_lttl] = get_specific_loudness_mid(exc_mid, G[gttq_lttl], A[gttq_lttl], alpha[gttq_lttl])
c@1 61 specific_loudness[greater_than_tl] = get_specific_loudness_high(exc_high)
c@1 62 else:
c@1 63 exc_mid = exc_i[greater_than_tq]
c@1 64 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 65
c@1 66 return specific_loudness
c@0 67
c@3 68 def get_specific_loudness_parameters(lenSig = 1):
c@3 69 """
c@3 70 Loads and returns the specific loudness values. If lenSig is specified, the parameters are shaped equal to the excitation signal to allow for
c@3 71 matrix elementwise operations between the parameters and signal. (Assumes excitation signal shape is [39, lenSig]).
c@3 72
c@3 73 Parameters:
c@3 74 * lenSig (type: numerical int) - the length of the excitation signal to be analysed. (Optional; Default = 1)
c@3 75
c@3 76 Returns:
c@3 77 * tq (type: numpy array of floats) - the threshold of quiet for each centre frequency of the ERBs
c@3 78 * G (type: numpy array of floats) - the frequency dependent gain values for each centre frequency of the ERBs
c@3 79 * A (type: numpy array of floats) - the frequency dependent A values for each centre frequency of the ERBs
c@3 80 * alpha (type: numpy array of floats) - the frequency dependent alpha values for each centre frequency of the ERBs
c@3 81 """
c@3 82
c@3 83 tq_dB, A, alpha = utils.load_sl_parameters() #load tq, A and alpha parameters
c@3 84 tq_dB = np.transpose(np.tile(tq_dB, (lenSig,1)))
c@3 85 tq = 10**(tq_dB / 10)
c@3 86 A = np.transpose(np.tile(A, (lenSig,1)))
c@3 87 alpha = np.transpose(np.tile(alpha, (lenSig,1)))
c@3 88 tq500_dB = 3.73 #threshold of quiet at 500Hz reference
c@3 89 G = 10**((tq500_dB - tq_dB)/10) #gain parameters
c@3 90
c@3 91 return tq, G, A, alpha
c@3 92
c@1 93 def get_specific_loudness_low(exc_low, G, tq, A, alpha):
c@3 94 """
c@3 95 Returns the specific loudness of the low level parts of the signal. Use get_specific_loudness_parameters() and specify lenSig
c@3 96 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 97 excitations.
c@3 98
c@3 99 e.g.,
c@3 100
c@3 101 # exc_i is the excitation intensity
c@3 102 lenSig = np.shape(exc_i)[-1] # find the length of the signal
c@3 103 tq, G, A, alpha = get_specific_loudness_parameters(lenSig) # get the shaped loudness parameters
c@3 104 less_than_tq = get_less_than_tq(exc_i, tq) # find which samples are lower level
c@3 105 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 106 # only process the low level part of the signal
c@3 107
c@3 108 Parameters:
c@3 109 * exc_low (type: array-like matrix of floats) - the lower level (less than or equal to tq) excitation pattern for each ERB
c@3 110 (Required)
c@3 111 * G (type: array-like matrix of floats) - the frequency dependent loudness gain parameters for each ERB, must be same shape
c@3 112 as exc_low. (Required)
c@3 113 * tq (type: array-like matrix of floats) - the frequency dependent threshold of quiet parameters for each ERB. Must be same
c@3 114 shape as exc_low. (Required)
c@3 115 * A (type: array-like matrix of floats) - the frequency dependent A parameters for each ERB. Must be same shape as exc_low.
c@3 116 * alpha (type: array-like matrix of floats) - the frequency dependent alpha parameters for each ERB. Must be same shape as
c@3 117 exc_low. (Required)
c@3 118
c@3 119 Returns:
c@3 120 * specific_loudness_low (type: array-like matrix of floats) - An array with dimensions equal to the exc_low containing the
c@3 121 specific loudness of the signal at levels below the threshold of quiet.
c@3 122 """
c@1 123
c@1 124 C = 0.047 #constant parameter
c@1 125 specific_loudness_low = C * ((2*exc_low)/(exc_low+tq))**1.5 * ((G * exc_low + A)**alpha - A**alpha)
c@1 126
c@1 127 return specific_loudness_low
c@1 128
c@1 129 def get_specific_loudness_mid(exc_mid, G, A, alpha):
c@3 130 """
c@3 131 Returns the specific loudness of the mid level parts of the signal.
c@3 132
c@3 133 e.g.,
c@3 134
c@3 135 # exc_i is the excitation intensity
c@3 136 lenSig = np.shape(exc_i)[-1] # find the length of the signal
c@3 137 tq, G, A, alpha = get_specific_loudness_parameters(lenSig) # get the shaped loudness parameters
c@3 138 less_than_tq = get_less_than_tq(exc_i, tq) # find which samples are lower level
c@3 139 greater_than_tq = ~less_than_tq # find which samples are greater than the threshold of quiet
c@3 140 greater_than_tl = get_greater_than_tl(exc_i) # find which samples are greater than the loud threshold
c@3 141 gttq_lttl = greater_than_tq[~greater_than_tl] # find which samples are mid level
c@3 142 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 143 # only process the mid level part of the signal
c@3 144
c@3 145 NOTE: The above is an example of use assuming the higher level processing IS NOT IGNORED. Use variable greater_than_tq if processing
c@3 146 higher levels equivalent to the mid.
c@3 147
c@3 148
c@3 149 Parameters:
c@3 150 * exc_mid (type: array-like matrix of floats) - the mid level (larger than tq (and, optionally less than high level threshold))
c@3 151 excitation pattern for each ERB (Required)
c@3 152 * G (type: array-like matrix of floats) - the frequency dependent loudness gain parameters for each ERB, must be same shape
c@3 153 as exc_low. (Required)
c@3 154 * A (type: array-like matrix of floats) - the frequency dependent A parameters for each ERB. Must be same shape as exc_low.
c@3 155 * alpha (type: array-like matrix of floats) - the frequency dependent alpha parameters for each ERB. Must be same shape as
c@3 156 exc_low. (Required)
c@3 157
c@3 158 Returns:
c@3 159 * specific_loudness_mid (type: array-like matrix of floats) - An array with dimensions equal to the exc_mid containing the
c@3 160 specific loudness of the signal at mid levels.
c@3 161 """
c@1 162
c@1 163 C = 0.047 #constant parameter
c@1 164 specific_loudness_mid = C * ((G * exc_mid + A)**alpha - A**alpha)
c@1 165
c@1 166 return specific_loudness_mid
c@1 167
c@1 168 def get_specific_loudness_high(exc_high):
c@1 169 """
c@3 170 Returns the specific loudness of the high level parts of the signal.
c@3 171
c@3 172 e.g.,
c@3 173
c@3 174 # exc_i is the excitation intensity
c@3 175 lenSig = np.shape(exc_i)[-1] # find the length of the signal
c@3 176 tq, G, A, alpha = get_specific_loudness_parameters(lenSig) # get the shaped loudness parameters
c@3 177 greater_than_tl = get_greater_than_tl(exc_i) # find which samples are greater than the loud threshold
c@3 178 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 179 # only process the mid level part of the signal
c@3 180
c@3 181 Parameters:
c@3 182 * exc_high (type: array-like matrix of floats) - the high level (larger than the threshold of high level) excitation pattern
c@3 183 for each ERB (Required)
c@3 184
c@3 185 Returns:
c@3 186 * specific_loudness_high (type: array-like matrix of floats) - An array with dimensions equal to the exc_high containing the
c@3 187 specific loudness of the signal at high levels.
c@1 188 """
c@1 189
c@1 190 C = 0.047 #constant parameter
c@1 191 specific_loudness_high = C * (exc_high / (1.04 * 10**6))**0.5
c@1 192
c@1 193 return specific_loudness_high
c@1 194
c@1 195 def get_greater_than_tl(exc_i):
c@1 196 """
c@1 197 A function to return if each element of the excitation intensity is greater than the threshold of loud.
c@1 198
c@1 199 Parameters:
c@1 200 * exc_i (type: array-like matrix of floats) - the input excitation intensity
c@1 201
c@1 202 Returns:
c@3 203 * le_tq (type: array-like matrix of booleans) - a boolean array with dimensions equal to the input
c@3 204 specifying if the excitation intensity is greater than the threshold of loud
c@1 205 """
c@1 206
c@1 207 lenSig = np.shape(exc_i)[-1]
c@1 208 g_tl = exc_i[:,:]>np.transpose(np.tile(10**10,(lenSig,39)))
c@1 209
c@1 210 return g_tl
c@1 211
c@1 212 def get_less_than_tq(exc_i, tq):
c@1 213 """
c@1 214 A function to return if each element of the excitation intensity is less than the threshold of quiet.
c@1 215
c@1 216 Parameters:
c@1 217 * exc_i (type: array-like matrix of floats) - the input excitation intensity
c@1 218 * tq (type: array-like matrix of floats) - the threshold of quiet for each ERB.
c@1 219
c@1 220 Returns:
c@1 221 * le_tq (type: array-like matrix of booleans) - a boolean array with dimensions equal to the input
c@1 222 specifying if the excitation intensity is less than the threshold of quiet
c@1 223 """
c@1 224
c@1 225 if (np.shape(exc_i)!=np.shape(tq)):
c@1 226 np.transpose(np.tile(exc_i,(np.shape(exc_i)[-1],1)))
c@1 227
c@1 228 le_tq = exc_i<=tq
c@1 229
c@1 230 return le_tq
c@1 231
c@1 232 def get_excitation_i(input, fs, SPL, rectify=False, verbose = False):
c@0 233 """
c@0 234 A function to calculate the excitation intensity of the input signal.
c@0 235
c@0 236 Parameters:
c@0 237 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required)
c@0 238 * fs (type: numerical) - sample frequency of the signal, input. (Required)
c@0 239 * SPL (type: double) - the sound pressure level (SPL) at 0 dBFS, e.g., the SPL of a sine
c@0 240 wave with peaks at amplitude 1 and troughs at amplitude -1. (Required)
c@0 241 * rectify (type: boolean) - Specifies whether to include half wave rectification, modelling the direction
c@0 242 of that the cochlear nerves vibrate.
c@0 243 True to include, False to ignore. (Optional; Default = False)
c@0 244
c@0 245 Returns:
c@0 246 * gtfs (type: numpy array of floats) - array with size ((39,) + np.shape(input)) containing the excitation
c@0 247 pattern (in sound intensity) for each ERB of input signal. The excitation pattern for the nth ERB can
c@0 248 be accessed with gtfs[n].
c@0 249 """
c@0 250
c@0 251 input = np.array(input)
c@0 252 inputOMFir = outMidFir(input)
c@0 253 inputPa = v_Pascal(inputOMFir, SPL)
c@4 254 b = gamma_tone_filter(fs)
c@4 255 gtfs = decomposition(inputPa, b, verbose = verbose)
c@0 256 if (rectify):
c@0 257 gtfs = half_rectification(gtfs)
c@0 258 gtfs = pa_i(gtfs)
c@0 259 gtfs = at_normalise(gtfs)
c@3 260 b,a = exp_smoothing(fs)
c@3 261 gtfs = sp.lfilter(b,a,gtfs)
c@0 262
c@0 263 return gtfs
c@0 264
c@4 265 def plot_excitation_response(input = None, fs = 44100, outMidFilt = True, gammatone = True, xscale = 'log', yscale = 'log'):
c@0 266 """
c@0 267 A function that plots the transfer function of the outer middle ear and each gammatone filter.
c@0 268
c@0 269 Parameters:
c@0 270 * fs (type: numerical) - the sampling frequency of the signal. (Optional; Default = 44100)
c@0 271 * outMidFilt (type: boolean) - filter the signal by the outer and middle ear FIR filter. (Optional; Default = True)
c@0 272 * xscale (type: string) - the scale of the frequency axis. Values are 'log' or 'linear'. (Optional; Default = 'log')
c@0 273 * yscale (type: string) - the scale of the amplitude axis. Values are 'log' or 'linear'. (Optional; Default = 'log')
c@0 274 """
c@1 275
c@4 276 if input == None:
c@4 277 input = np.zeros((np.ceil(fs)))
c@1 278 input[0] = 1
c@4 279
c@0 280 if(outMidFilt): input = outMidFir(input)
c@4 281 if(gammatone):
c@4 282 b = gamma_tone_filter(fs)
c@4 283 input = decomposition(input, b)
c@4 284 #input = holdsworthGamma(input,fs)
c@4 285 numPlot = range(np.shape(input)[0])
c@4 286 else:
c@4 287 numPlot = (0,)
c@4 288 input = input.reshape(1,len(input))
c@4 289
c@4 290 for i in numPlot:
c@4 291 utils.plot_fft(input[i],xscale, yscale, False)
c@0 292
c@0 293 plt.show()
c@0 294
c@4 295 return
c@0 296
c@0 297 def get_modulation_i(input, fs):
c@0 298 """
c@0 299 A function to calculate the modulation intensity of the input intensity signal. The function implements a
c@0 300 filter bank of bandpass filters with cut off frequencies ranging from 0.25 to 16 Hz.
c@0 301
c@0 302 Parameters:
c@0 303 * input (type: array-like matrix of floats) - the input intensity signal.
c@0 304 E.g., use get_excitation_i() to obtain excitation intensity and use as input.
c@0 305 * fs (type: numerical) - sampling frequency of input signal
c@0 306
c@0 307 Returns:
c@0 308 * y (type: numpy array of floats) - array with size ((10,) + np.shape(input)) containing the
c@0 309 modulation intensity of the signal at each modulation filter. The modulation intensity for the nth filter can
c@0 310 be accessed with y[n].
c@0 311 """
c@0 312
c@0 313 input = np.array(input)
c@0 314 b = fir_antialias(fs)
c@0 315 input_lp = sp.lfilter(b,(1),input_fr)
c@0 316 input_ds = downsample(input_lp, fs)
c@0 317 fc = np.array(utils.exp_sequence(-2,4,10))
c@0 318 bw = fc/2
c@0 319 y = decomposition(input_ds, fs, fc, bw)
c@0 320
c@0 321 return y
c@0 322
c@0 323 def outMidFir(input):
c@0 324 """
c@0 325 A function to filter the input signal with the response of the outer and middle ear.
c@0 326
c@0 327 Parameters:
c@0 328 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required)
c@0 329
c@0 330 Returns:
c@0 331 * y (type: numpy array of floats) - array with dimensions equal to the input signal filtered by the response of
c@0 332 the outer and middle ear.
c@0 333 """
c@0 334
c@0 335 input = np.array(input)
c@0 336 b = utils.load_outMidFir_coeff()
c@0 337 y = sp.lfilter(b, (1), input)
c@0 338
c@0 339 return y
c@0 340
c@4 341 def gamma_tone_filter(fs):
c@0 342 """
c@0 343 A function to filter to decompose the input signal into 39 different gammatones filtered signals modelling the ERBs.
c@0 344
c@0 345 Parameters:
c@0 346 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required)
c@0 347 * fs (type: numerical) - sample frequency of the signal, input. (Required)
c@0 348
c@0 349 Returns:
c@0 350 * y (type: numpy array of floats) - array with size ((39),np.shape(input)) containing the impulse response of the
c@0 351 signal at each gammatone filter. The response at the nth gammatone filter can be accessed by y[n].
c@0 352 """
c@0 353
c@4 354 nerbs = 39
c@4 355 erbs = np.array(range(1,nerbs+1))
c@4 356 fc = (10**(erbs/21.366)-1)/0.004368
c@4 357 bw = 24.673 * (1 + 0.004368*fc)
c@4 358 N = 4
c@4 359 filterLength = 4096
c@4 360 t = 1.0*np.array(range(filterLength))/fs
c@4 361
c@4 362 gain=((1.019*bw*(2.0*np.pi)/float(fs))**4)/6.0
c@4 363
c@4 364 PI = N * np.arctan(1)
c@4 365
c@4 366 b = np.zeros((nerbs,filterLength))
c@4 367
c@4 368 for i in range(39):
c@4 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)
c@4 370
c@4 371 return b
c@4 372
c@4 373 def holdsworthGamma(input, fs):
c@4 374 """
c@4 375
c@4 376 """
c@0 377 input = np.array(input)
c@4 378 input = input + 0j
c@4 379
c@4 380 T = 1.0/fs
c@4 381
c@4 382 ERBs = np.array(range(1,40))
c@4 383 f0 = (10**(ERBs/21.4)-1)/4.37e-3
c@4 384
c@4 385 inLen = len(input)
c@4 386 b = 24.673 * (1 + 0.004368*f0)
c@4 387 k = np.array(range(inLen)) + 0j
c@4 388 out = np.zeros((39,inLen))
c@4 389
c@4 390 for erb in range(39):
c@4 391
c@4 392 zArr = input*np.exp(-2*np.pi*1j*f0[erb]*k*T)
c@4 393 wArr = np.zeros((inLen+1))
c@4 394
c@4 395 for i in range(1,inLen+1):
c@4 396 wArr[i] = wArr[i-1] + (1 - np.exp(-2*np.pi*b[erb]*T))*(zArr[i-1] - wArr[i-1])
c@4 397
c@4 398 out[erb] = (wArr[1:]*np.exp(2*np.pi*1j*f0[erb]*k*T)).real
c@4 399
c@4 400 return out
c@4 401
c@0 402
c@0 403 def v_Pascal(input, SPL):
c@0 404 """
c@0 405 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 406
c@0 407 Parameters:
c@0 408 * input (type: array-like matrix of floats) - signal normalised to an amplitude range of -1 to 1. (Required)
c@0 409 * SPL (type: double) - the sound pressure level (SPL) at 0 dBFS, e.g., the SPL of a sine
c@0 410 wave with peaks at amplitude 1 and troughs at amplitude -1. (Required)
c@0 411
c@0 412 Returns:
c@0 413 * y (type: numpy array of floats) - array with dimensions equal to the input signal containing the input represented
c@0 414 as a pressure signal.
c@0 415 """
c@0 416
c@0 417 input = np.array(input)
c@1 418 y = np.sign(input)*(0.00002*10**(np.log10(np.abs(input))+SPL/20))
c@0 419
c@0 420 return y
c@0 421
c@0 422 def pa_i(input, C=406):
c@0 423 """
c@0 424 A function to convert a pressure signal (unit: Pascal) to an intensity signal.
c@0 425
c@0 426 Parameters:
c@0 427 * input (type: array-like matrix of floats) - pressure signal (unit: Pascal) (Required)
c@0 428 * C (type: double) - the acoustic impedance of the air (Optional; Default = 406)
c@0 429
c@0 430 Returns:
c@0 431 * y (type: numpy array of floats) - array with dimensions equal to the input signal containing the input represented
c@0 432 as a pressure signal.
c@0 433 """
c@0 434
c@0 435 input = np.array(input)
c@0 436 y = (input**2) / C
c@0 437
c@0 438 return y
c@0 439
c@0 440 def at_normalise(input):
c@0 441 """
c@0 442 A function to normalise an intensity signal with the audibility threshold.
c@0 443
c@0 444 Parameters:
c@0 445 * input (type: array-like matrix of floats) - intensity signal (unit: Pascal) (Required)
c@0 446
c@0 447 Returns:
c@0 448 * y (type: numpy array of floats) - array with dimensions equal to the input signal containing the input normalised
c@0 449 with the audibility threshold.
c@0 450 """
c@0 451
c@0 452 input = np.array(input)
c@0 453 y = input / 1*(10**12)
c@0 454
c@1 455 return y
c@0 456
c@0 457 def downsample(input, factor=100):
c@0 458 """
c@0 459 A function to downsample a signal, input, with sampling frequency, fs, by a downsample factor of factor.
c@0 460
c@0 461 NOTE: It is advised to use the fir_antialias() function before downsampling to remove any high frequencies
c@0 462 which would otherwise represented as low frequencies due to aliasing.
c@0 463
c@0 464 Parameters:
c@0 465 * input (type: array-like matrix of floats) - input signal. (Required)
c@0 466 * factor - downsample factor (Optional; Default = 100)
c@0 467
c@0 468 Returns:
c@0 469 * output (type: numpy array of floats) - array with outer dimensions equivalent to the to the input, and
c@0 470 inner dimension equal to np.floor(lenIn / factor) where lenIn is the length of the inner dimension.
c@0 471 """
c@0 472
c@0 473 input = np.array(input)
c@0 474 shapeIn = np.shape(input)
c@0 475 nDim = np.shape(shapeIn)
c@0 476 lenIn = shapeIn[nDim[0]-1]
c@0 477 lenOut = np.floor(lenIn / factor)
c@0 478 n = np.linspace(0,lenIn,lenOut, endpoint=False).astype(np.int)
c@0 479 output = input[...,n]
c@0 480
c@0 481 return output
c@0 482
c@0 483 def half_rectification(input):
c@0 484 """
c@0 485 A function which performs a half-wave rectification on the input signal.
c@0 486
c@0 487 Parameters:
c@0 488 * input (type: array-like matrix of floats) - input signal. (Required)
c@0 489
c@0 490 Returns:
c@0 491 * y (type: numpy array of floats) - an array with dimensions of input containing the half-wave rectification of
c@0 492 input.
c@0 493 """
c@0 494
c@0 495
c@0 496 y = np.array(input)
c@0 497 y[y<0] = 0
c@0 498
c@0 499 return y
c@0 500
c@4 501 def decomposition(input, b, a = None, verbose = False):
c@0 502 """
c@4 503 A function to run the input through a bandpass filter bank with parameters defined by the b and a coefficints.
c@0 504
c@0 505 Parameters:
c@0 506 * input (type: array-like matrix of floats) - input signal. (Required)
c@4 507 * b (type: array-like matrix of floats) - the b coefficients of each filter in shape b[numOfFilters][numOfCoeffs]. (Required)
c@4 508 * a (type: array-like matrix of floats) - the a coefficients of each filter in shape a[numOfFilters][numOfCoeffs].
c@4 509 If not specified, the filter is treated as a FIR filter. (Optional; Default = 1)
c@4 510 * verbose (type: boolean) - determines whether to display the current subroutine/progress of the procedure.
c@4 511 (Optional; Default = False)
c@4 512
c@4 513 Returns:
c@4 514 * y (type: numpy array of floats) - an array with inner dimensions equal to that of the input and outer dimension equal to
c@4 515 the length of fc (i.e. the number of bandpass filters in the bank) containing the outputs to each filter. The output
c@4 516 signal of the nth filter can be accessed using y[n].
c@4 517 """
c@4 518
c@4 519 input = np.array(input)
c@4 520 bShape = np.shape(b)
c@4 521 nFilters = bShape[0]
c@4 522
c@4 523 if a == None:
c@4 524 a = np.ones(nFilters)
c@4 525
c@4 526 shape = (nFilters,) + np.shape(input)
c@4 527 shape = shape[0:]
c@4 528 y = np.zeros(shape)
c@4 529
c@4 530 if(verbose): print "Running decomposition."
c@4 531 for i in range(nFilters):
c@4 532 if(verbose): print str(100.0*i/nFilters) + "% complete."
c@4 533 x = deepcopy(input)
c@4 534 y[i] = sp.lfilter(b[i],a[i],x)
c@4 535
c@4 536 return y
c@4 537
c@4 538 def get_Modulation_filter_bank_coefficients(fs, fc, bw, order = 1024, verbose = False):
c@4 539 """
c@4 540 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 541 bandpass filter is designed by defining the centre frequencies, fc, and bandwidths, bw.
c@4 542
c@4 543 Parameters:
c@0 544 * fs (type: numerical) - the sampling frequency of the input signal. (Required)
c@0 545 * fc (type: array-like vector of floats) - the centre off frequencies (unnormalised) of each bandpass filter.
c@0 546 The length of this vector determines the number of filters in the bank.
c@0 547 * bw (type: array-like vector of floats) - the bandwidths (unnormalised) of each bandpass filter. Must be equal
c@0 548 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 549 ignored.
c@0 550 * order (type: numerical int) - the order of the filter (number of taps minus 1) (Optional; Default = 1024)
c@0 551 * verbose (type: boolean) - determines whether to display the current subroutine/progress of the procedure.
c@0 552 (Optional; Default = False)
c@0 553
c@0 554 Returns:
c@4 555 * b (type: numpy array of floats) - an array of size order + 1 (i.e. a coefficient for each tap)
c@0 556 """
c@4 557
c@4 558
c@0 559 nFreqs = len(fc)
c@4 560
c@0 561 if(verbose): print "Running frequency decomposition."
c@4 562
c@0 563 for i in range(nFreqs):
c@0 564 if(verbose): print str(100.0*i/nFreqs) + "% complete."
c@0 565 low = fc[i]-bw[i]/2;
c@0 566 high = fc[i]+bw[i]/2;
c@0 567 if(verbose): print "Low: " + str(low) + "; High: " + str(high)
c@0 568 b = fir_bandpass(low, high, fs, order, verbose)
c@4 569
c@4 570 return b
c@0 571
c@3 572 def exp_smoothing(fs, tc = 0.01):
c@3 573 """
c@3 574 Designs an exponential filter, y[n] = alpha*x[n] - -(1-alpha)*y[n-1], where alpha = T/(tc+T), where T
c@3 575 is the inverse of the sampling frequency and time constant, tc, is specified.
c@3 576
c@3 577 Parameters:
c@3 578 * fs (type: numerical) - sampling frequency of the signal to be filtered (Required)
c@3 579 * tc (type: numerical) - the time constant of the filter. (Optional; Default = 0.01)
c@3 580
c@3 581 Returns:
c@3 582 * b (type: numerical) - the coefficient of x[n]. Equal to alpha.
c@3 583 * 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 584 """
c@3 585
c@3 586 T = 1.0/fs
c@3 587 alpha = T/(tc + T)
c@3 588 b = [alpha]
c@3 589 a = [1, -(1-alpha)]
c@3 590
c@3 591 return b, a
c@3 592
c@3 593 def antialias_fir(fs, fc=100, order=64):
c@3 594 """
c@3 595 A function which returns the b coefficients for a lowpass fir filter with specified requirements.
c@3 596 Made specifically to remove aliasing when downsampling, but can be used for any application that
c@3 597 requires a lowpass filter.
c@3 598
c@3 599 Parameters:
c@3 600 * fs (type: numerical) - sampling frequency of the signal to be filtered (Required)
c@3 601 * fc (type: numerical) - unnormalised cut off frequency of the filter (Optional; Default = 100)
c@3 602 * order (type: numerical int) - the order of the filter (number of taps minus 1) (Optional; Default = 64)
c@3 603
c@3 604 Returns:
c@3 605 * b (type: numpy array of floats) - an array of size order + 1 (i.e. a coefficient for each tap)
c@3 606 """
c@3 607
c@3 608 nyquist = 0.5*fs
c@3 609 fcNorm = fc/nyquist
c@3 610 b = sp.firwin(order+1, fcNorm)
c@3 611
c@3 612 return b
c@3 613
c@4 614 def fir_bandpass(low, high, fs, order = 4096, verbose = False):
c@0 615 """
c@0 616 A function which returns the b coefficients for a bandpass fir filter with specified requirements.
c@0 617
c@0 618 Parameters:
c@0 619 * low - the lower cutoff frequency of the filter. (Required)
c@0 620 * high - the upper cutoff frequency of the filter. (Required)
c@0 621 * fs (type: numerical) - sampling frequency of the signal to be filtered. (Required)
c@0 622 * order (type: numerical int) - the order of the filter (number of taps minus 1) (Optional; Default = 1024)
c@0 623 * verbose (type: boolean) - determines whether to display the current progress (or info on the current subroutine)
c@0 624 of the procedure. (Optional; Default = False)
c@0 625
c@0 626 Returns:
c@0 627 * b (type: numpy array of floats) - an array of size order + 1 (i.e. a coefficient for each tap).
c@0 628 """
c@0 629
c@0 630 nyquist = 0.5*fs
c@0 631 lowNorm = low/nyquist
c@0 632 highNorm = high/nyquist
c@0 633 if(verbose): print "Low: " + str(lowNorm) + "; High: " + str(highNorm)
c@0 634 b = sp.firwin(order+1, [lowNorm, highNorm], pass_zero=False)
c@0 635
c@0 636 return b