Source code for analysis.KurtosisAnalysis

from __future__ import print_function, division
import os
import numpy as np
import logging
from scipy import signal
from numpy.lib import stride_tricks
import pdb

from fileops import pathops

from Analysis import Analysis

logger = logging.getLogger(__name__)


[docs]class KurtosisAnalysis(Analysis):
""" Kurtosis descriptor class for generation of Kurtosis audio analysis. This descriptor calculates the temporal kurtosis for overlapping grains of an AnalysedAudioFile object. A full definition of kurtosis analysis can be found in the documentation. Arguments: - analysis_group: the HDF5 file group to use for the storage of the analysis. - config: The configuration module used to configure the analysis """ def __init__(self, AnalysedAudioFile, frames, analysis_group, config=None): super(KurtosisAnalysis, self).__init__(AnalysedAudioFile,frames, analysis_group, 'kurtosis') self.logger = logging.getLogger(__name__+'.{0}Analysis'.format(self.name)) # Store reference to the file to be analysed self.AnalysedAudioFile = AnalysedAudioFile if config: self.window_size = config.kurtosis["window_size"] * self.AnalysedAudioFile.samplerate / 1000 self.overlap = 1. / config.kurtosis["overlap"] try: variance = self.AnalysedAudioFile.analyses["variance"] except KeyError: raise KeyError("Variance analysis is required for Kurtosis " "analysis.") self.analysis_group = analysis_group self.logger.info("Creating kurtosis analysis for {0}".format(self.AnalysedAudioFile.name)) self.create_analysis(frames, variance.analysis['frames'][:], self.window_size, overlapFac=self.overlap) @staticmethod def create_kurtosis_analysis( frames, variance, window_size=512, window=signal.hanning, overlapFac=0.5 ): """ Calculate the Kurtosis values of windowed segments of the audio file and save to disk. """ if hasattr(frames, '__call__'): frames = frames() # Calculate the period of the window in hz # lowest_freq = 1.0 / window_size # Filter frequencies lower than the period of the window # filter = ButterFilter() # filter.design_butter(lowest_freq, self.AnalysedAudioFile.samplerate) # TODO: Fix filter # frames = filter.filter_butter(frames) hopSize = int(window_size - np.floor(overlapFac * window_size)) # zeros at beginning (thus center of 1st window should be for sample nr. 0) samples = np.append(np.zeros(np.floor(window_size/2.0)), frames) # cols for windowing cols = np.ceil((len(samples) - window_size) / float(hopSize)) + 1 # zeros at end (thus samples can be fully covered by frames) samples = np.append(samples, np.zeros(window_size)) frames = stride_tricks.as_strided( samples, shape=(cols, window_size), strides=(samples.strides[0]*hopSize, samples.strides[0]) ).copy() if window: win = window(window_size) frames *= win frame_mean = np.mean(frames, axis=1) variance_sqrd = variance**2 a = ((1 / window_size)) * np.sum(((frames-np.vstack(frame_mean))**4), axis=1) kurtosis = a / variance_sqrd kurtosis -= 3 return kurtosis def hdf5_dataset_formatter(self, *args, **kwargs): ''' Formats the output from the analysis method to save to the HDF5 file. ''' samplerate = self.AnalysedAudioFile.samplerate kurtosis = self.create_kurtosis_analysis(*args, **kwargs) kurtosis_times = self.calc_kurtosis_frame_times(kurtosis, args[0], samplerate) return ({'frames': kurtosis, 'times': kurtosis_times}, {}) @staticmethod def calc_kurtosis_frame_times(kurtosisframes, sample_frames, samplerate): """Calculate times for frames using sample size and samplerate.""" if hasattr(sample_frames, '__call__'): sample_frames = sample_frames() # Get number of frames for time and frequency timebins = kurtosisframes.shape[0] # Create array ranging from 0 to number of time frames scale = np.arange(timebins+1) # divide the number of samples by the total number of frames, then # multiply by the frame numbers. kurtosis_times = (float(sample_frames.shape[0])/float(timebins)) * scale[:-1].astype(float) # Divide by the samplerate to give times in seconds kurtosis_times = kurtosis_times / samplerate return kurtosis_times