def morlet_multi(freqs, widths, samplerates, sampling_windows=7, complete=True): """ Calculate Morlet wavelets with the total energy normalized to 1. Calls the scipy.signal.wavelet.morlet() function to generate Morlet wavelets with the specified frequencies, samplerates, and widths (in cycles); see the docstring for the scipy morlet function for details. These wavelets are normalized before they are returned. Parameters ---------- freqs : {float, array_like of floats} The frequencies of the Morlet wavelets. widths : {float, array_like floats} The width(s) of the wavelets in cycles. If only one width is passed in, all wavelets have the same width. If len(widths)==len(freqs), each frequency is paired with a corresponding width. If 1<len(widths)<len(freqs), len(freqs) must be evenly divisible by len(widths) (i.e., len(freqs)%len(widths)==0). In this case widths are repeated such that (1/len(widths))*len(freq) neigboring wavelets have the same width -- e.g., if len(widths)==2, the the first and second half of the wavelets have widths of widths[0] and width[1] respectively, and if len(widths)==3 the first, middle, and last third of wavelets have widths of widths[0], widths[1], and widths[2] respectively. samplerates : {float, array_like floats} The sample rate(s) of the signal (e.g., 200 Hz). sampling_windows : {float, array_like of floates},optional How much of the wavelets is sampled. As sampling_window increases, the number of samples increases and thus the samples near the edge approach zero increasingly closely. If desired different values can be specified for different wavelets (the syntax for multiple sampling windows is the same as for widths). One value >= 7 is recommended. complete : {bool},optional Whether to generate a complete or standard approximation to the complete version of a Morlet wavelet. Complete should be True, especially for low (<=5) values of width. See scipy.signal.wavelet.morlet() for details. Returns ------- A 2-D (frequencies * samples) array of Morlet wavelets. Notes ----- The in scipy versions <= 0.6.0, the scipy.signal.wavelet.morlet() code contains a bug. Until it is fixed in a stable release, this code calls a local fixed version of the scipy function. Examples -------- >>> wavelet = morlet_multi(10,5,200) >>> wavelet.shape (1, 112) >>> wavelet = morlet_multi([10,20,30],5,200) >>> wavelet.shape (3, 112) >>> wavelet = morlet_multi([10,20,30],[5,6,7],200) >>> wavelet.shape (3, 112) """ # ensure the proper dimensions freqs = np.atleast_1d(freqs) widths = np.atleast_1d(widths) samplerates = np.atleast_1d(samplerates).astype(np.float64) sampling_windows = np.atleast_1d(sampling_windows) # check input: if len(freqs) < 1: raise ValueError("At least one frequency must be specified!") if len(widths) < 1 or len(freqs)%len(widths) != 0: raise ValueError("Freqs and widths are not compatible: len(freqs) must "+ "be evenly divisible by len(widths).\n"+ "len(freqs) = "+str(len(freqs))+"\nlen(widths) = "+ str(len(widths))) if len(samplerates) < 1 or len(freqs)%len(samplerates) != 0: raise ValueError("Freqs and samplerates are not compatible:"+ "len(freqs) must be evenly divisible by"+ "len(samplerates).\nlen(freqs) = "+str(len(freqs))+ "\nlen(samplerates) = "+str(len(samplerates))) if len(sampling_windows) < 1 or len(freqs)%len(sampling_windows) != 0: raise ValueError("Freqs and sampling_windows are not compatible:"+ "len(freqs) must be evenly divisible by"+ "len(sampling_windows).\nlen(freqs) = "+str(len(freqs))+ "\nlen(sampling_windows) = "+str(len(sampling_windows))) # make len(widths)==len(freqs): widths = widths.repeat(len(freqs)/len(widths)) # make len(samplerates)==len(freqs): samplerates = samplerates.repeat(len(freqs)/len(samplerates)) # make len(sampling_windows)==len(freqs): sampling_windows = sampling_windows.repeat(len(freqs)/len(sampling_windows)) # std. devs. in the time domain: st = widths/(2*np.pi*freqs) # determine number of samples needed: samples = np.ceil(st*samplerates*sampling_windows) # each scale depends on frequency, samples, width, and samplerates: scales = (freqs*samples)/(2.*widths*samplerates) # generate list of unnormalized wavelets: wavelets = [morlet_wavelet(samples[i],w=widths[i],s=scales[i], complete=complete) for i in xrange(len(scales))] # generate list of energies for the wavelets: energies = [np.sqrt(np.sum(np.power(np.abs(wavelets[i]),2.))/samplerates[i]) for i in xrange(len(scales))] # normalize the wavelets by dividing each one by its energy: norm_wavelets = [wavelets[i]/energies[i] for i in xrange(len(scales))] return norm_wavelets
def morlet_multi(freqs, widths, samplerate, sampling_window=7, complete=True): """ Calculate Morlet wavelets with the total energy normalized to 1. Calls the scipy.signal.wavelet.morlet() function to generate Morlet wavelets with the specified frequencies, samplerate, and widths (in cycles); see the docstring for the scipy morlet function for details. These wavelets are normalized before they are returned. Parameters ---------- freqs : {int, float, array_like of ints or floats} The frequencies of the Morlet wavelets. widths : {int, float, array_like of ints or floats} The width(s) of the wavelets in cycles. If only one width is passed in, all wavelets have the same width. If len(widths)==len(freqs), each frequency is paired with a corresponding width. If 1<len(widths)<len(freqs), len(freqs) must be evenly divisible by len(widths) (i.e., len(freqs)%len(widths)==0). In this case widths are repeated such that (1/len(widths))*len(freq) neigboring wavelets have the same width -- e.g., if len(widths)==2, the the first and second half of the wavelets have widths of widths[0] and width[1] respectively, and if len(widths)==3 the first, middle, and last third of wavelets have widths of widths[0], widths[1], and widths[2] respectively. samplerate : {float} The sample rate of the signal (e.g., 200 Hz). sampling_window : {float},optional How much of the wavelet is sampled. As sampling_window increases, the number of samples increases and thus the samples near the edge approach zero increasingly closely. The number of samples are determined from the wavelet(s) with the largest standard deviation in the time domain. All other wavelets are therefore guaranteed to approach zero better at the edges. A value >= 7 is recommended. complete : {bool},optional Whether to generate a complete or standard approximation to the complete version of a Morlet wavelet. Complete should be True, especially for low (<=5) values of width. See scipy.signal.wavelet.morlet() for details. Returns ------- A 2-D (frequencies * samples) array of Morlet wavelets. Notes ----- The in scipy versions <= 0.6.0, the scipy.signal.wavelet.morlet() code contains a bug. Until it is fixed in a stable release, this code calls a local fixed version of the scipy function. Examples -------- >>> wavelet = morlet_multi(10,5,200) >>> wavelet.shape (1, 112) >>> wavelet = morlet_multi([10,20,30],5,200) >>> wavelet.shape (3, 112) >>> wavelet = morlet_multi([10,20,30],[5,6,7],200) >>> wavelet.shape (3, 112) """ # ensure the proper dimensions freqs = N.atleast_1d(freqs) widths = N.atleast_1d(widths) # make len(widths)==len(freqs): widths = widths.repeat(len(freqs)/len(widths)) if len(widths) != len(freqs): raise ValueError("Freqs and widths are not compatible: len(freqs) must "+ "be evenly divisible by len(widths).\n"+ "len(freqs) = "+str(len(freqs))+"\nlen(widths) = "+ str(len(widths)/(len(freqs)/len(widths)))) # std. devs. in the time domain: st = widths/(2*N.pi*freqs) # determine number of samples needed based on wavelet with maximum # standard deviation in time domain samples = N.ceil(N.max(st)*samplerate*sampling_window) # determine the scales of the wavelet (cf. # scipy.signal.wavelets.morlet docstring): scales = (freqs*samples)/(2.*widths*samplerate) #wavelets = N.empty((len(freqs),samples),dtype=N.complex128) wavelets = N.empty((len(freqs),samples),dtype=N.complex) for i in xrange(len(freqs)): wavelets[i] = morlet_wavelet(samples,w=widths[i],s=scales[i], complete=complete) #wavelets = N.array([morlet_wavelet(samples,w=widths[i],s=scales[i], # complete=complete) # for i in xrange(len(scales))]) energy = N.sqrt(N.sum(N.power(N.abs(wavelets),2.),axis=1)/samplerate) norm_factors = N.vstack([1./energy]*samples).T return wavelets*norm_factors