Time series =========== Biomedical signals are typically equidistantly sampled time-series. Such signals can be defined by an array of signal values and a sampling frequency [Hz]. The `nnsa` package contains a TimeSeries class which provides a useful interface for dealing with time series. This script demonstrates how to use the TimeSeries class. Author: Tim Hermans (tim-hermans@hotmail.com). Link to script: `containers/time_series.py `_ .. code-block:: python import matplotlib.pyplot as plt import numpy as np from nnsa import TimeSeries from nnsa.preprocessing.filter import RemezFIR plt.close('all') A TimeSeries is defined at least by a signal array and a sampling frequency. More optional parameters are possible, see the documentation of the TimeSeries class. .. code-block:: python # Create some dummy data. ts = TimeSeries(signal=np.random.rand(400*250), fs=128, label='C4', unit='uV') # Printing the TimeSeries object will display an informative description of the object. print(ts) We can do several types of prepocessing, such as filtering and resampling. For most of such functions, you can typically choose whether to do this inplace or not. .. code-block:: python # Let's look at filtering. To filter the data, you first need to define a filter based on the nnsa.FilterBase() # class. Common filters are already implemented, see the nnsa.preprocessing.filter. # Create a FIR filter with the Remez algorithm and filter the signal. fir = RemezFIR( fs=None, # We do not need to pass fs here, this will be automatically set when we apply the filter to a TimeSeries. passband=[0.6, 40], stopband=[0.1, 47], passband_ripple=1, stopband_attenuation=40) Now its very easy to apply this filter to the TimeSeries. You can choose whether you want to do zero-phase filtering (`filtfilt`) or just one-way filtering (`filter`): .. code-block:: python # Filter using normal (one-way) filtering. ts_filter = ts.filter(fir) # Filter using zero-phase filtering. ts_filtfilt = ts.filtfilt(fir) Resampling is also easy. You can choose two methods for resampling: (anti-aliasing) "polyphase_filtering" or "interpolation". If you there is a risk of aliasing, the polyphase_filtering might be the safest option. .. code-block:: python # Resample filtered signal using polyphase filtering (equivalent to MATLAB's resample(x, p, q)). ts_res = ts.resample(fs_new=30, method='polyphase_filtering') # Resample filtered signal using interpolation. ts_int = ts.resample(fs_new=30, method='interpolation') Segmentation can also be done easily by defining the segment length and overlap in seconds: .. code-block:: python # Segment the signal in 30 second parts by creating a generator, yielding TimeSeries objects. segment_generator = ts.segment(30, overlap=0) # Yields TimeSeries with the next 30 second segment. # You can iterate over the segments by iterating over segment_generator. # E.g. you can collect the signal data of all segments in an array: segment_array = np.asarray([seg.signal for seg in segment_generator]) # Dimensions (segments, time) Of course, you can also obtain the signal data in a numpy array to do other processing (and optionally put is back into an TimeSeries format, if convenient). .. code-block:: python # Get the signal data as a numpy array (1D vector). signal = ts.signal # The corresponding sampling frequency, time array, and label can be obtained, too: fs = ts.fs time = ts.time label = ts.label We can easily plot a TimeSeries. .. code-block:: python begin = 300 # Begin time in seconds. end = 330 # End time in seconds. plt.figure() ts.plot(begin=begin, end=end, label='original') # Plot the filtered signal. ts_filtfilt.plot(begin=begin, end=end, label='filtered') # Plot the resampled (by filtering) signal. ts_res.plot(':', begin=begin, end=end, label='resample by filtering') # Add legend to the plot (we already passed the labels when plotting). plt.legend() The TimeSeries class has a bunch of methods to easily compute some features or do some analysis. .. code-block:: python # For example, ompute the power spectral density (PSD) of the entire signal (see also psd examples). psd_results = ts.psd() # Returns PsdResult object. # Due to chaining we sometimes need just one line of code to do several steps: plt.figure() ts.filtfilt(fir).resample(30).psd().plot() For a list of all functions, see the documentation of TimeSeries: https://nnsa.readthedocs.io/en/latest/examples.containers.eeg_dataset.html