def test_waveletcoefficients(self): data = numpy.random.random((10, 10)) ts = time_series.TimeSeries(data=data) dt = spectral.WaveletCoefficients( source=ts, mother='morlet', sample_period=7.8125, frequencies=[0.008, 0.028, 0.048, 0.068], normalisation="energy", q_ratio=5.0, array_data=numpy.random.random((10, 10)), ) dt.configure() summary_info = dt.summary_info self.assertEqual(summary_info['Maximum frequency'], 0.068) self.assertEqual(summary_info['Minimum frequency'], 0.008) self.assertEqual(summary_info['Normalisation'], 'energy') self.assertEqual(summary_info['Number of scales'], 4) self.assertEqual(summary_info['Q-ratio'], 5.0) self.assertEqual(summary_info['Sample period'], 7.8125) self.assertEqual(summary_info['Spectral type'], 'WaveletCoefficients') self.assertEqual(summary_info['Wavelet type'], 'morlet') self.assertEqual(dt.q_ratio, 5.0) self.assertEqual(dt.sample_period, 7.8125) self.assertEqual(dt.shape, (10, 10)) self.assertTrue(dt.source is not None)
def test_waveletcoefficients(self): data = numpy.random.random((10, 10)) ts = time_series.TimeSeries(data=data) dt = spectral.WaveletCoefficients( source=ts, mother='morlet', sample_period=7.8125, frequencies=numpy.array([0.008, 0.028, 0.048, 0.068]), normalisation="energy", q_ratio=5.0, array_data=numpy.random.random((10, 10)), ) # dt.configure() summary_info = dt.summary_info() assert summary_info['Maximum frequency'] == 0.068 assert summary_info['Minimum frequency'] == 0.008 assert summary_info['Normalisation'], 'energy' assert summary_info['Number of scales'] == 4 assert summary_info['Q-ratio'] == 5.0 assert summary_info['Sample period'] == 7.8125 assert summary_info['Spectral type'] == 'WaveletCoefficients' assert summary_info['Wavelet type'] == 'morlet' assert dt.q_ratio == 5.0 assert dt.sample_period == 7.8125 assert dt.array_data.shape == (10, 10) assert dt.source is not None
def evaluate(self): """ Calculate the continuous wavelet transform of time_series. """ cls_attr_name = self.__class__.__name__ + ".time_series" self.time_series.trait["data"].log_debug(owner=cls_attr_name) ts_shape = self.time_series.data.shape if self.frequencies.step == 0: LOG.warning( "Frequency step can't be 0! Trying default step, 2e-3.") self.frequencies.step = 0.002 freqs = numpy.arange(self.frequencies.lo, self.frequencies.hi, self.frequencies.step) if (freqs.size == 0) or any( freqs <= 0.0 ): #TODO: Maybe should limit number of freqs... ~100 is probably a reasonable upper bound. LOG.warning("Invalid frequency range! Falling back to default.") util.log_debug_array(LOG, freqs, "freqs") self.frequencies = basic.Range(lo=0.008, hi=0.060, step=0.002) freqs = numpy.arange(self.frequencies.lo, self.frequencies.hi, self.frequencies.step) util.log_debug_array(LOG, freqs, "freqs") sample_rate = self.time_series.sample_rate # Duke: code below is as given by Andreas Spiegler, I've just wrapped # some of the original argument names nf = len(freqs) temporal_step = max( (1, iround(self.sample_period / self.time_series.sample_period))) nt = int(numpy.ceil(ts_shape[0] / temporal_step)) if not isinstance(self.q_ratio, numpy.ndarray): Q_ratio = self.q_ratio * numpy.ones((1, nf)) if numpy.nanmin(Q_ratio) < 5: msg = "Q_ratio must be not lower than 5 !" LOG.error(msg) raise Exception(msg) if numpy.nanmax(freqs) > sample_rate / 2.0: msg = "Sampling rate is too low for the requested frequency range !" LOG.error(msg) raise Exception(msg) #TODO: This isn't used, but min frequency seems like it should be important... Check with A.S. # fmin = 3.0 * numpy.nanmin(Q_ratio) * sample_rate / numpy.pi / nt sigma_f = freqs / Q_ratio sigma_t = 1.0 / (2.0 * numpy.pi * sigma_f) if self.normalisation == 'energy': Amp = 1.0 / numpy.sqrt( sample_rate * numpy.sqrt(numpy.pi) * sigma_t) elif self.normalisation == 'gabor': Amp = numpy.sqrt(2.0 / numpy.pi) / sample_rate / sigma_t coef_shape = (nf, nt, ts_shape[1], ts_shape[2], ts_shape[3]) coef = numpy.zeros(coef_shape, dtype=numpy.complex128) util.log_debug_array(LOG, coef, "coef") scales = numpy.arange(0, nf, 1) for i in scales: f0 = freqs[i] SDt = sigma_t[(0, i)] A = Amp[(0, i)] x = numpy.arange(0, 4.0 * SDt * sample_rate, 1) / sample_rate wvlt = A * numpy.exp(-x**2 / (2.0 * SDt**2)) * numpy.exp( 2j * numpy.pi * f0 * x) wvlt = numpy.hstack((numpy.conjugate(wvlt[-1:0:-1]), wvlt)) #util.log_debug_array(LOG, wvlt, "wvlt") for var in range(ts_shape[1]): for node in range(ts_shape[2]): for mode in range(ts_shape[3]): data = self.time_series.data[:, var, node, mode] wt = signal.convolve(data, wvlt, 'same') #util.log_debug_array(LOG, wt, "wt") res = wt[0::temporal_step] #NOTE: this is a horrible horrible quick hack (alas, a solution) to avoid broadcasting errors # when using dt and sample periods which are not powers of 2. coef[i, :, var, node, mode] = res if len( res) == nt else res[:coef.shape[1]] util.log_debug_array(LOG, coef, "coef") spectra = spectral.WaveletCoefficients( source=self.time_series, mother=self.mother, sample_period=self.sample_period, frequencies=self.frequencies, normalisation=self.normalisation, q_ratio=self.q_ratio, array_data=coef, use_storage=False) return spectra
def compute_continuous_wavelet_transform(time_series, frequencies, sample_period, q_ratio, normalisation, mother): """ # type: (TimeSeries, Range, float, float, str, str) -> WaveletCoefficients Calculate the continuous wavelet transform of time_series. Parameters __________ time_series : TimeSeries The timeseries to which the wavelet is to be applied. frequencies : Range The frequency resolution and range returned. Requested frequencies are converted internally into appropriate scales. sample_period : float The sampling period of the computed wavelet spectrum. q_ratio : float NFC. Must be greater than 5. Ratios of the center frequencies to bandwidths. normalisation : str The type of normalisation for the resulting wavet spectrum. Default is 'energy', options are: 'energy'; 'gabor'. mother : str The mother wavelet function used in the transform. """ ts_shape = time_series.data.shape if frequencies.step == 0: log.warning("Frequency step can't be 0! Trying default step, 2e-3.") frequencies.step = 0.002 freqs = numpy.arange(frequencies.lo, frequencies.hi, frequencies.step) if (freqs.size == 0) or any(freqs <= 0.0): # TODO: Maybe should limit number of freqs... ~100 is probably a reasonable upper bound. log.warning("Invalid frequency range! Falling back to default.") log.debug("freqs") log.debug(narray_describe(freqs)) frequencies = Range(lo=0.008, hi=0.060, step=0.002) freqs = numpy.arange(frequencies.lo, frequencies.hi, frequencies.step) log.debug("freqs") log.debug(narray_describe(freqs)) sample_rate = time_series.sample_rate # Duke: code below is as given by Andreas Spiegler, I've just wrapped # some of the original argument names nf = len(freqs) temporal_step = max( (1, ReferenceBackend.iround(sample_period / time_series.sample_period))) nt = int(numpy.ceil(ts_shape[0] / temporal_step)) if not isinstance(q_ratio, numpy.ndarray): new_q_ratio = q_ratio * numpy.ones((1, nf)) if numpy.nanmin(new_q_ratio) < 5: msg = "q_ratio must be not lower than 5 !" log.error(msg) raise Exception(msg) if numpy.nanmax(freqs) > sample_rate / 2.0: msg = "Sampling rate is too low for the requested frequency range !" log.error(msg) raise Exception(msg) # TODO: This isn't used, but min frequency seems like it should be important... Check with A.S. # fmin = 3.0 * numpy.nanmin(q_ratio) * sample_rate / numpy.pi / nt sigma_f = freqs / new_q_ratio sigma_t = 1.0 / (2.0 * numpy.pi * sigma_f) if normalisation == 'energy': Amp = 1.0 / numpy.sqrt(sample_rate * numpy.sqrt(numpy.pi) * sigma_t) elif normalisation == 'gabor': Amp = numpy.sqrt(2.0 / numpy.pi) / sample_rate / sigma_t coef_shape = (nf, nt, ts_shape[1], ts_shape[2], ts_shape[3]) coef = numpy.zeros(coef_shape, dtype=numpy.complex128) log.debug("coef") log.debug(narray_describe(coef)) scales = numpy.arange(0, nf, 1) for i in scales: f0 = freqs[i] SDt = sigma_t[(0, i)] A = Amp[(0, i)] x = numpy.arange(0, 4.0 * SDt * sample_rate, 1) / sample_rate wvlt = A * numpy.exp(-x**2 / (2.0 * SDt**2)) * numpy.exp( 2j * numpy.pi * f0 * x) wvlt = numpy.hstack((numpy.conjugate(wvlt[-1:0:-1]), wvlt)) # util.self.log_debug_array(self.log, wvlt, "wvlt") for var in range(ts_shape[1]): for node in range(ts_shape[2]): for mode in range(ts_shape[3]): data = time_series.data[:, var, node, mode] wt = signal.convolve(data, wvlt, 'same') # util.self.log_debug_array(self.log, wt, "wt") res = wt[0::temporal_step] # NOTE: this is a horrible horrible quick hack (alas, a solution) to avoid broadcasting errors # when using dt and sample periods which are not powers of 2. coef[i, :, var, node, mode] = res if len(res) == nt else res[:coef.shape[1]] log.debug("coef") log.debug(narray_describe(coef)) spectra = spectral.WaveletCoefficients(source=time_series, mother=mother, sample_period=sample_period, frequencies=frequencies.to_array(), normalisation=normalisation, q_ratio=q_ratio, array_data=coef) return spectra