c@0
|
1 """
|
c@0
|
2 A utility module to assist cortical_model.py with general procedures, e.g., file reading and writing.
|
c@0
|
3
|
c@0
|
4 Packaged dependencies:
|
c@0
|
5 * erb.dat
|
c@0
|
6 * outMidFir.dat
|
c@1
|
7 * tq.dat
|
c@0
|
8
|
c@0
|
9 External dependencies:
|
c@0
|
10 * scipy
|
c@0
|
11 * numpy
|
c@0
|
12 * matplotlib
|
c@0
|
13 """
|
c@0
|
14
|
c@0
|
15 import numpy as np
|
c@0
|
16 import scipy.io.wavfile as wave
|
c@0
|
17 import matplotlib.pyplot as plt
|
c@0
|
18 import scipy.fftpack as fft
|
c@0
|
19
|
c@0
|
20 def load_erb_data():
|
c@0
|
21 """
|
c@0
|
22 Loads and returns 39 ERB frequencies and bandwidths
|
c@0
|
23
|
c@0
|
24 Parameters:
|
c@0
|
25 NONE
|
c@0
|
26
|
c@0
|
27 Returns:
|
c@0
|
28 * fc (type: numpy array of floats) - a vector of length 39 with elements containing
|
c@0
|
29 the centre frequencies of each ERB.
|
c@0
|
30 * bw (type: numpy array of floats) - a vector of length 39 with elements containing
|
c@0
|
31 the bandwidths of each ERB.
|
c@0
|
32
|
c@0
|
33 Dependencies:
|
c@0
|
34 * erb.dat (place in the same folder as utils.pyc)
|
c@0
|
35 """
|
c@1
|
36 # read data from a text file
|
c@0
|
37 data=np.loadtxt("erb.dat",delimiter=",")
|
c@0
|
38
|
c@0
|
39 # load centre frequencies from the first column into fc
|
c@0
|
40 fc=np.array(data[:,0])
|
c@0
|
41 # load bandwidths from the second column into bw
|
c@0
|
42 bw=np.array(data[:,1])
|
c@0
|
43
|
c@0
|
44 return fc,bw
|
c@0
|
45
|
c@0
|
46 def load_outMidFir_coeff():
|
c@0
|
47 """
|
c@0
|
48 Loads and returns 39 ERB frequencies and bandwidths
|
c@0
|
49
|
c@0
|
50 Parameters:
|
c@0
|
51 NONE
|
c@0
|
52
|
c@0
|
53 Returns:
|
c@0
|
54 * b (type: numpy array of floats) - a vector of length 4097 containing the impulse
|
c@0
|
55 response of the outer middle ear.
|
c@0
|
56
|
c@0
|
57 Dependencies:
|
c@0
|
58 * outMidFir.dat (place in the same folder as utils.pyc)
|
c@0
|
59 """
|
c@0
|
60
|
c@1
|
61 b=np.array(np.loadtxt("outMidFir.dat", delimiter=","))
|
c@0
|
62
|
c@0
|
63 return b
|
c@0
|
64
|
c@1
|
65 def load_sl_parameters():
|
c@1
|
66 """
|
c@1
|
67 Loads the loudness parameters for each ERB fc into a tuple. A shortcut for load_tq_data(), load_A_data() and load_alpha_data().
|
c@1
|
68
|
c@1
|
69 Parameters:
|
c@1
|
70 NONE
|
c@1
|
71
|
c@1
|
72 Returns:
|
c@1
|
73 * tq (type: numpy array of floats) - a vector of length 39 containing the threshold excitation
|
c@1
|
74 intensity in quietat each ERB centre frequency
|
c@1
|
75 * A (type: numpy array of floats) - a vector of length 39 containing the parameter A for each ERB fc
|
c@1
|
76 * alpha (type: numpy array of floats) - a vector of length 39 containing the parameter alpha for each ERB fc
|
c@1
|
77
|
c@1
|
78 Dependencies:
|
c@1
|
79 * tq.dat (place in the same folder as utils.pyc)
|
c@1
|
80 * A.dat (place in the same folder as utils.pyc)
|
c@1
|
81 * alpha.dat (place in the same folder as utils.pyc)
|
c@1
|
82 """
|
c@5
|
83 tq_dB = load_tqdB_data()
|
c@1
|
84 A = load_A_data()
|
c@1
|
85 alpha = load_alpha_data()
|
c@1
|
86
|
c@5
|
87 return tq_dB, A, alpha
|
c@1
|
88
|
c@5
|
89 def load_tqdB_data():
|
c@1
|
90 """
|
c@1
|
91 Loads and returns the excitation threshold of quiet for each ERB fc.
|
c@1
|
92
|
c@1
|
93 Parameters:
|
c@1
|
94 NONE
|
c@1
|
95
|
c@1
|
96 Returns:
|
c@1
|
97 * tq (type: numpy array of floats) - a vector of length 39 containing the threshold excitation
|
c@1
|
98 intensity in quietat each ERB centre frequency
|
c@1
|
99
|
c@1
|
100 Dependencies:
|
c@1
|
101 * tq.dat (place in the same folder as utils.pyc)
|
c@1
|
102 """
|
c@1
|
103
|
c@5
|
104 tq = np.array(np.loadtxt("tq_dB.dat",delimiter=","))
|
c@1
|
105
|
c@1
|
106 return tq
|
c@1
|
107
|
c@1
|
108 def load_A_data():
|
c@1
|
109 """
|
c@1
|
110 Loads and returns the excitation A parameters for each ERB fc.
|
c@1
|
111
|
c@1
|
112 Parameters:
|
c@1
|
113 NONE
|
c@1
|
114
|
c@1
|
115 Returns:
|
c@1
|
116 * A (type: numpy array of floats) - a vector of length 39 containing the parameter A for each ERB fc
|
c@1
|
117
|
c@1
|
118 Dependencies:
|
c@1
|
119 * A.dat (place in the same folder as utils.pyc)
|
c@1
|
120 """
|
c@1
|
121
|
c@1
|
122 A = np.array(np.loadtxt("A.dat",delimiter=","))
|
c@1
|
123
|
c@1
|
124 return A
|
c@1
|
125
|
c@1
|
126 def load_alpha_data():
|
c@1
|
127 """
|
c@1
|
128 Loads and returns the excitation alpha parameters for each ERB fc.
|
c@1
|
129
|
c@1
|
130 Parameters:
|
c@1
|
131 NONE
|
c@1
|
132
|
c@1
|
133 Returns:
|
c@1
|
134 * alpha (type: numpy array of floats) - a vector of length 39 containing the parameter alpha for each ERB fc
|
c@1
|
135
|
c@1
|
136 Dependencies:
|
c@1
|
137 * alpha.dat (place in the same folder as utils.pyc)
|
c@1
|
138 """
|
c@1
|
139
|
c@1
|
140 alpha = np.array(np.loadtxt("alpha.dat",delimiter=","))
|
c@1
|
141
|
c@1
|
142 return alpha
|
c@1
|
143
|
c@0
|
144 def exp_sequence(start, stop, n, base=2):
|
c@0
|
145 """
|
c@0
|
146 Creates a linear sequence with n points starting from start and ending at stop. For each
|
c@1
|
147 element in the sequence, i, the output sequence is 2**i, generating an exponential sequence
|
c@0
|
148 with base 2.
|
c@0
|
149
|
c@0
|
150 Parameters:
|
c@0
|
151 * start (type: numerical int) - determines the first element of the sequence, i.e.,
|
c@1
|
152 base**start. (Required)
|
c@0
|
153 * stop (type: numerical int) - determines the last element of the sequence, i.e.,
|
c@1
|
154 base**stop. (Required)
|
c@0
|
155 * n (type = numerical int) - determines the number of elements in the sequence. (Required)
|
c@0
|
156 * base (type: numerical) - determines the exponential base. (Optional; Default = 2)
|
c@0
|
157
|
c@0
|
158 Returns:
|
c@0
|
159 * seq - the exponential sequence
|
c@0
|
160 """
|
c@0
|
161
|
c@0
|
162 seq = [base**x for x in np.linspace(start,stop,n)]
|
c@0
|
163
|
c@0
|
164 return seq
|
c@0
|
165
|
c@0
|
166 def wavread(file):
|
c@0
|
167 """
|
c@0
|
168 Reads the audio data from a wav file and converts it to floating point ranging from -1 to 1.
|
c@0
|
169
|
c@0
|
170 Parameters:
|
c@0
|
171 * file (type: string) - the name of the wav file to read from. (Required)
|
c@0
|
172
|
c@0
|
173 Returns:
|
c@0
|
174 * fs (type: numerical) - the sampling frequency of the signal storied in file
|
c@0
|
175 * data (type: numpy array of floats) - the data of the signal stored in file normalised
|
c@0
|
176 to an amplitude range of -1 to 1.
|
c@0
|
177 """
|
c@0
|
178
|
c@0
|
179 fs,data = wave.read(file)
|
c@1
|
180 data = np.array(int_to_nfloat(data))
|
c@0
|
181
|
c@0
|
182 return fs,data
|
c@0
|
183
|
c@0
|
184 def wavwrite(file, fs, data, precision = 16):
|
c@0
|
185 """
|
c@0
|
186 Unnormalises the audio data to a specified integer precision and converts to an int, then
|
c@0
|
187 writes the audio data to a wav file. (E.g., if 16-bit precision, then highest amplitude
|
c@1
|
188 is equal to 2**16).
|
c@0
|
189
|
c@0
|
190 Parameters:
|
c@0
|
191 * file (type: string) - the name of the wav file to write to. (Required)
|
c@0
|
192 * fs (type: numerical) - the sampling frequency of the signal. (Required)
|
c@0
|
193 * data (type: array-like matrix of floats) - the signal data normalised from -1 to 1. The signal will be clipped if not
|
c@0
|
194 in this range. (Required)
|
c@0
|
195 * precision (type: numerical int)- the bit precision to store at. Can only be 16 or 32 bit, because that is
|
c@0
|
196 all scipy allows.
|
c@0
|
197
|
c@0
|
198 Returns:
|
c@0
|
199 NONE
|
c@0
|
200
|
c@0
|
201 TODO explore WAVE package to be allow for 24bit precision.
|
c@0
|
202 """
|
c@0
|
203
|
c@0
|
204 data[data>1] = 1
|
c@0
|
205 data[data<-1] = -1
|
c@0
|
206
|
c@0
|
207 if(precision == 16):
|
c@0
|
208 dtype = np.int16
|
c@0
|
209 elif(precision == 32):
|
c@0
|
210 dtype = np.int32
|
c@0
|
211 else:
|
c@0
|
212 print "Error: precision can only be 16 or 32 bit due to scipy package."
|
c@0
|
213 return
|
c@0
|
214
|
c@0
|
215 data = nfloat_to_int(data)
|
c@0
|
216 wave.write(file, fs, data)
|
c@0
|
217
|
c@0
|
218 return
|
c@0
|
219
|
c@0
|
220 def plot_fft(x, xscale = 'log', yscale = 'log', show = True):
|
c@0
|
221 """
|
c@0
|
222 Plots the fft of signal x. If the figure is not shown, the current plot is held to allow other plots to
|
c@0
|
223 be added to the same figure.
|
c@0
|
224
|
c@0
|
225 Parameters:
|
c@0
|
226 * x (type: array-like matrix of floats) - the signal to be analysed. (Required)
|
c@0
|
227 * xscale (type: string) - the scale of the frequency axis. Values are 'log' or 'linear'. (Optional; Default = 'log')
|
c@0
|
228 * yscale (type: string) - the scale of the amplitude axis. Values are 'log' or 'linear'. (Optional; Default = 'log')
|
c@0
|
229 * show (type: boolean) - specifies whether the figure should be shown. If False, the current plot will be held so
|
c@0
|
230 other plots can be added to the figure. (Optional; Default = True)
|
c@0
|
231
|
c@0
|
232 Returns:
|
c@0
|
233 NONE
|
c@0
|
234 """
|
c@0
|
235
|
c@4
|
236 plt.gca().set_xscale(xscale)
|
c@4
|
237 plt.gca().set_yscale(yscale)
|
c@1
|
238
|
c@1
|
239 x = np.array(x)
|
c@0
|
240 fftx = np.absolute(fft.fft(x))
|
c@0
|
241 plt.plot(range(np.shape(x)[0]),fftx)
|
c@0
|
242 if(show):
|
c@0
|
243 plt.show()
|
c@0
|
244 else:
|
c@0
|
245 plt.hold(True)
|
c@0
|
246
|
c@0
|
247 return
|
c@0
|
248
|
c@1
|
249 def plot_waveform(x, show = True):
|
c@1
|
250 """
|
c@1
|
251 Plots the waveform of signal x. If the figure is not shown, the current plot is held to allow other plots to
|
c@1
|
252 be added to the same figure.
|
c@1
|
253
|
c@1
|
254 Parameters:
|
c@1
|
255 * x (type: array-like matrix of floats) - the signal to be plotted. (Required)
|
c@1
|
256 * show (type: boolean) - specifies whether the figure should be shown. If False, the current plot will be held so
|
c@1
|
257 other plots can be added to the figure. (Optional; Default = True)
|
c@1
|
258
|
c@1
|
259 Returns:
|
c@1
|
260 NONE
|
c@1
|
261 """
|
c@1
|
262
|
c@1
|
263 x = np.array(x)
|
c@1
|
264 plt.plot(x)
|
c@1
|
265
|
c@1
|
266 if(show): plt.show()
|
c@1
|
267 else: plt.hold(True)
|
c@1
|
268
|
c@1
|
269 return
|
c@1
|
270
|
c@1
|
271 def int_to_nfloat(input, outputtype=np.float32):
|
c@0
|
272 """
|
c@0
|
273 Convert integer with to floating point with a range from -1 to 1.
|
c@0
|
274
|
c@0
|
275 Parameters:
|
c@0
|
276 * input (type: array-like matrix of ints) - a signed integer array. (Required)
|
c@0
|
277 dtype : the output datatype. (Optional; Default = np.float32)
|
c@0
|
278
|
c@0
|
279 Returns:
|
c@0
|
280 * y (type: array-like matrix of floats) - a float array normalised to a
|
c@0
|
281 range of -1 to 1.
|
c@0
|
282 """
|
c@0
|
283
|
c@0
|
284 input = np.array(input)
|
c@0
|
285 assert input.dtype.kind == 'i', "'input' must be an array-like matrix of integers."
|
c@1
|
286 outputtype = np.dtype(outputtype)
|
c@0
|
287 inputdtype = np.dtype(type(input[0]))
|
c@1
|
288 input = input.astype(outputtype)
|
c@0
|
289
|
c@0
|
290 input[input > 0] = input[input > 0] / np.iinfo(inputdtype).max
|
c@0
|
291 input[input < 0] = input[input < 0] / -np.iinfo(inputdtype).min
|
c@0
|
292
|
c@0
|
293 y = input
|
c@0
|
294 return y
|
c@0
|
295
|
c@0
|
296 def nfloat_to_int(input, type=np.int16):
|
c@0
|
297 """
|
c@0
|
298 Convert a float array with amplitude ranging from -1 to 1 to a unnormalised signed
|
c@0
|
299 integer array with specified precision.
|
c@0
|
300
|
c@0
|
301 Parameters:
|
c@0
|
302 * input (type: array-like matrix of floats) - a float array. (Required)
|
c@0
|
303 dtype : the output datatype (also determines the precision).
|
c@0
|
304 (Optional; Default = np.int16)
|
c@0
|
305
|
c@0
|
306 Returns:
|
c@0
|
307 * y (type: array-like matrix of ints) - an unnormalised to a
|
c@0
|
308 range of -1 to 1.
|
c@0
|
309 """
|
c@0
|
310
|
c@0
|
311 input = np.array(input)
|
c@0
|
312 assert input.dtype.kind == 'f', "'input' must be an array of floats!"
|
c@0
|
313
|
c@1
|
314 input[input > 0] = input[ input > 0 ] * np.iinfo(type).max
|
c@1
|
315 input[input < 0] = input[ input < 0 ] * -np.iinfo(type).min
|
c@0
|
316
|
c@0
|
317 y = input.astype(type)
|
c@0
|
318
|
c@0
|
319 return y |