From 9fbb4fa216ff0ade9647a7b3d38a16f4e9258856 Mon Sep 17 00:00:00 2001 From: agricolab Date: Sun, 20 Mar 2022 20:55:49 +0100 Subject: [PATCH] update docs --- .gitignore | 3 + artacs/kernel.py | 272 ++++++++++-------- artacs/template.py | 201 ++++++++----- .../_autosummary/artacs.kernel.doctree | 3 - doc/build/doctrees/environment.pickle | 3 - doc/build/doctrees/index.doctree | 3 - doc/build/html/.buildinfo | 3 - .../html/_autosummary/artacs.kernel.html | 3 - doc/build/html/_modules/artacs/kernel.html | 3 - doc/build/html/_modules/index.html | 3 - .../_autosummary/artacs.kernel.rst.txt | 3 - doc/build/html/_sources/index.rst.txt | 3 - doc/build/html/_static/ajax-loader.gif | 3 - doc/build/html/_static/basic.css | 3 - doc/build/html/_static/comment-bright.png | 3 - doc/build/html/_static/comment-close.png | 3 - doc/build/html/_static/comment.png | 3 - doc/build/html/_static/css/badge_only.css | 3 - doc/build/html/_static/css/theme.css | 3 - doc/build/html/_static/doctools.js | 3 - .../html/_static/documentation_options.js | 3 - doc/build/html/_static/down-pressed.png | 3 - doc/build/html/_static/down.png | 3 - doc/build/html/_static/file.png | 3 - .../html/_static/fonts/Lato/lato-bold.eot | 3 - .../html/_static/fonts/Lato/lato-bold.ttf | 3 - .../html/_static/fonts/Lato/lato-bold.woff | 3 - .../html/_static/fonts/Lato/lato-bold.woff2 | 3 - .../_static/fonts/Lato/lato-bolditalic.eot | 3 - .../_static/fonts/Lato/lato-bolditalic.ttf | 3 - .../_static/fonts/Lato/lato-bolditalic.woff | 3 - .../_static/fonts/Lato/lato-bolditalic.woff2 | 3 - .../html/_static/fonts/Lato/lato-italic.eot | 3 - .../html/_static/fonts/Lato/lato-italic.ttf | 3 - .../html/_static/fonts/Lato/lato-italic.woff | 3 - .../html/_static/fonts/Lato/lato-italic.woff2 | 3 - .../html/_static/fonts/Lato/lato-regular.eot | 3 - .../html/_static/fonts/Lato/lato-regular.ttf | 3 - .../html/_static/fonts/Lato/lato-regular.woff | 3 - .../_static/fonts/Lato/lato-regular.woff2 | 3 - .../fonts/RobotoSlab/roboto-slab-v7-bold.eot | 3 - .../fonts/RobotoSlab/roboto-slab-v7-bold.ttf | 3 - .../fonts/RobotoSlab/roboto-slab-v7-bold.woff | 3 - .../RobotoSlab/roboto-slab-v7-bold.woff2 | 3 - .../RobotoSlab/roboto-slab-v7-regular.eot | 3 - .../RobotoSlab/roboto-slab-v7-regular.ttf | 3 - .../RobotoSlab/roboto-slab-v7-regular.woff | 3 - .../RobotoSlab/roboto-slab-v7-regular.woff2 | 3 - .../_static/fonts/fontawesome-webfont.eot | 3 - .../_static/fonts/fontawesome-webfont.svg | 3 - .../_static/fonts/fontawesome-webfont.ttf | 3 - .../_static/fonts/fontawesome-webfont.woff | 3 - .../_static/fonts/fontawesome-webfont.woff2 | 3 - doc/build/html/_static/img/recovery_ecg.png | 3 - doc/build/html/_static/img/upper_limb_ecg.jpg | 3 - doc/build/html/_static/jquery-3.2.1.js | 3 - doc/build/html/_static/jquery.js | 3 - doc/build/html/_static/js/modernizr.min.js | 3 - doc/build/html/_static/js/theme.js | 3 - doc/build/html/_static/minus.png | 3 - doc/build/html/_static/plus.png | 3 - doc/build/html/_static/pygments.css | 3 - doc/build/html/_static/searchtools.js | 3 - doc/build/html/_static/underscore-1.3.1.js | 3 - doc/build/html/_static/underscore.js | 3 - doc/build/html/_static/up-pressed.png | 3 - doc/build/html/_static/up.png | 3 - doc/build/html/_static/websupport.js | 3 - doc/build/html/genindex.html | 3 - doc/build/html/index.html | 3 - doc/build/html/objects.inv | 3 - doc/build/html/py-modindex.html | 3 - doc/build/html/search.html | 3 - doc/build/html/searchindex.js | 3 - doc/source/api.rst | 3 + doc/source/examples.rst | 3 + doc/source/index.rst | 4 +- example.py | 28 ++ doc/build/html/.nojekyll => test/__init__.py | 0 test/test.py | 152 ---------- test/test_kernel.py | 172 +++++++++++ 81 files changed, 500 insertions(+), 551 deletions(-) delete mode 100644 doc/build/doctrees/_autosummary/artacs.kernel.doctree delete mode 100644 doc/build/doctrees/environment.pickle delete mode 100644 doc/build/doctrees/index.doctree delete mode 100644 doc/build/html/.buildinfo delete mode 100644 doc/build/html/_autosummary/artacs.kernel.html delete mode 100644 doc/build/html/_modules/artacs/kernel.html delete mode 100644 doc/build/html/_modules/index.html delete mode 100644 doc/build/html/_sources/_autosummary/artacs.kernel.rst.txt delete mode 100644 doc/build/html/_sources/index.rst.txt delete mode 100644 doc/build/html/_static/ajax-loader.gif delete mode 100644 doc/build/html/_static/basic.css delete mode 100644 doc/build/html/_static/comment-bright.png delete mode 100644 doc/build/html/_static/comment-close.png delete mode 100644 doc/build/html/_static/comment.png delete mode 100644 doc/build/html/_static/css/badge_only.css delete mode 100644 doc/build/html/_static/css/theme.css delete mode 100644 doc/build/html/_static/doctools.js delete mode 100644 doc/build/html/_static/documentation_options.js delete mode 100644 doc/build/html/_static/down-pressed.png delete mode 100644 doc/build/html/_static/down.png delete mode 100644 doc/build/html/_static/file.png delete mode 100644 doc/build/html/_static/fonts/Lato/lato-bold.eot delete mode 100644 doc/build/html/_static/fonts/Lato/lato-bold.ttf delete mode 100644 doc/build/html/_static/fonts/Lato/lato-bold.woff delete mode 100644 doc/build/html/_static/fonts/Lato/lato-bold.woff2 delete mode 100644 doc/build/html/_static/fonts/Lato/lato-bolditalic.eot delete mode 100644 doc/build/html/_static/fonts/Lato/lato-bolditalic.ttf delete mode 100644 doc/build/html/_static/fonts/Lato/lato-bolditalic.woff delete mode 100644 doc/build/html/_static/fonts/Lato/lato-bolditalic.woff2 delete mode 100644 doc/build/html/_static/fonts/Lato/lato-italic.eot delete mode 100644 doc/build/html/_static/fonts/Lato/lato-italic.ttf delete mode 100644 doc/build/html/_static/fonts/Lato/lato-italic.woff delete mode 100644 doc/build/html/_static/fonts/Lato/lato-italic.woff2 delete mode 100644 doc/build/html/_static/fonts/Lato/lato-regular.eot delete mode 100644 doc/build/html/_static/fonts/Lato/lato-regular.ttf delete mode 100644 doc/build/html/_static/fonts/Lato/lato-regular.woff delete mode 100644 doc/build/html/_static/fonts/Lato/lato-regular.woff2 delete mode 100644 doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot delete mode 100644 doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf delete mode 100644 doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff delete mode 100644 doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 delete mode 100644 doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot delete mode 100644 doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf delete mode 100644 doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff delete mode 100644 doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 delete mode 100644 doc/build/html/_static/fonts/fontawesome-webfont.eot delete mode 100644 doc/build/html/_static/fonts/fontawesome-webfont.svg delete mode 100644 doc/build/html/_static/fonts/fontawesome-webfont.ttf delete mode 100644 doc/build/html/_static/fonts/fontawesome-webfont.woff delete mode 100644 doc/build/html/_static/fonts/fontawesome-webfont.woff2 delete mode 100644 doc/build/html/_static/img/recovery_ecg.png delete mode 100644 doc/build/html/_static/img/upper_limb_ecg.jpg delete mode 100644 doc/build/html/_static/jquery-3.2.1.js delete mode 100644 doc/build/html/_static/jquery.js delete mode 100644 doc/build/html/_static/js/modernizr.min.js delete mode 100644 doc/build/html/_static/js/theme.js delete mode 100644 doc/build/html/_static/minus.png delete mode 100644 doc/build/html/_static/plus.png delete mode 100644 doc/build/html/_static/pygments.css delete mode 100644 doc/build/html/_static/searchtools.js delete mode 100644 doc/build/html/_static/underscore-1.3.1.js delete mode 100644 doc/build/html/_static/underscore.js delete mode 100644 doc/build/html/_static/up-pressed.png delete mode 100644 doc/build/html/_static/up.png delete mode 100644 doc/build/html/_static/websupport.js delete mode 100644 doc/build/html/genindex.html delete mode 100644 doc/build/html/index.html delete mode 100644 doc/build/html/objects.inv delete mode 100644 doc/build/html/py-modindex.html delete mode 100644 doc/build/html/search.html delete mode 100644 doc/build/html/searchindex.js create mode 100644 doc/source/api.rst create mode 100644 doc/source/examples.rst create mode 100644 example.py rename doc/build/html/.nojekyll => test/__init__.py (100%) delete mode 100644 test/test.py create mode 100644 test/test_kernel.py diff --git a/.gitignore b/.gitignore index 2c13608..476eef8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,6 @@ data/* *.pyc .spyproject/ *.egg-info +doc/build/* +.vscode +doc/source/_autosummary/* \ No newline at end of file diff --git a/artacs/kernel.py b/artacs/kernel.py index 4e568ee..cdc7019 100644 --- a/artacs/kernel.py +++ b/artacs/kernel.py @@ -31,6 +31,8 @@ Conf Proc IEEE Eng Med Biol Soc 2015, 3436–3439. https://doi.org/10.1109/EMBC.2015.7319131 +[2]: Guggenberger, R., & Gharabaghi, A. (2021). Comb filters for the removal of transcranial current stimulation artifacts from single channel EEG recordings. Current Directions in Biomedical Engineering, 7(2), 383–386. https://doi.org/10.1515/cdbme-2021-2097 + Application ----------- @@ -51,9 +53,7 @@ Object-oriented implementation ------------------------------ -There exists also an object-oriented implementation as follows:: - - kernel = +There exists also an object-oriented implementation (see :class:`~.CombKernel`) """ @@ -63,9 +63,10 @@ from warnings import warn from scipy import signal from artacs.tools import resample_by_fs, resample_by_count + # %% -def _estimate_prms_from_kernel(kernel:ndarray) -> Tuple[int, int]: - '''estimate period and width from kernel +def _estimate_prms_from_kernel(kernel: ndarray) -> Tuple[int, int]: + """estimate period and width from kernel args ---- @@ -79,64 +80,77 @@ def _estimate_prms_from_kernel(kernel:ndarray) -> Tuple[int, int]: width:int number of weight values in each direction - ''' - - - period = np.unique(np.diff(np.where(kernel!=0)[0])) + """ + + period = np.unique(np.diff(np.where(kernel != 0)[0])) if len(period) != 1: - raise ValueError('Multiple or no periods recognized in kernel' + - 'Was the kernel correctly constructed?') - + raise ValueError( + "Multiple or no periods recognized in kernel" + + "Was the kernel correctly constructed?" + ) + period = int(period) - left_width = (kernel[:kernel.shape[0]//2]<0).sum() - right_width = (kernel[kernel.shape[0]//2:]<0).sum() - + left_width = (kernel[: kernel.shape[0] // 2] < 0).sum() + right_width = (kernel[kernel.shape[0] // 2 :] < 0).sum() + if left_width == 0: width = right_width elif right_width == 0: width = left_width elif right_width == left_width: - width = left_width # both need to be equal, so it doesn't matter + width = left_width # both need to be equal, so it doesn't matter else: - raise ValueError('Kernel presents with unclear direction.' + - 'Was the kernel correctly constructed?') - + raise ValueError( + "Kernel presents with unclear direction." + + "Was the kernel correctly constructed?" + ) + return period, width + # %% -def _weigh_exp(width:int) -> ndarray: - 'create exponential weights' - weights = signal.exponential(((width-1)*2)+1)[:width] - weights /= (weights.sum()) +def _weigh_exp(width: int) -> ndarray: + "create exponential weights" + weights = signal.exponential(((width - 1) * 2) + 1)[:width] + weights /= weights.sum() return weights -def _weigh_linear(width:int) -> ndarray: - 'create linear weights' - weights = np.linspace(1/width, 1, num=width) - weights /= (weights.sum()) + +def _weigh_linear(width: int) -> ndarray: + "create linear weights" + weights = np.linspace(1 / width, 1, num=width) + weights /= weights.sum() return weights -def _weigh_gaussian(width:int, sigma:float=1) -> ndarray: - 'create gaussian weights' - weights = signal.gaussian(width*2, sigma)[0:width] - weights /= ( weights.sum()) + +def _weigh_gaussian(width: int, sigma: float = 1) -> ndarray: + "create gaussian weights" + weights = signal.gaussian(width * 2, sigma)[0:width] + weights /= weights.sum() return weights -def _weigh_uniform(width:int) -> ndarray: - 'create uniform weights' + +def _weigh_uniform(width: int) -> ndarray: + "create uniform weights" weights = np.ones(width) - weights /= ( weights.sum()) + weights /= weights.sum() return weights -def _weigh_not(width:int) -> ndarray: - 'create zero weights' + +def _weigh_not(width: int) -> ndarray: + "create zero weights" weights = np.zeros(width) return weights -def create_kernel(freq:int, fs:int, width:int, - left_mode:str='uniform', - right_mode:str='uniform') -> ndarray: - '''create kernel from parameters + +def create_kernel( + freq: int, + fs: int, + width: int, + left_mode: str = "uniform", + right_mode: str = "uniform", +) -> ndarray: + """create kernel from parameters args ---- @@ -160,39 +174,43 @@ def create_kernel(freq:int, fs:int, width:int, :func:`~.filter_1d` - ''' - in_period = fs/freq - period = int(np.ceil(in_period)) + """ + in_period = fs / freq + period = int(np.ceil(in_period)) if in_period != period: - warn ('Only integer periods are natively supported.' + - 'Will auto-resample to higher sampling rate') - fs = int(period * freq) - - weighfoos = {'uniform':_weigh_uniform, - 'uni':_weigh_uniform, - 'none':_weigh_not, - 'zero':_weigh_not, - 'gauss':_weigh_gaussian, - 'normal':_weigh_gaussian, - 'linear':_weigh_linear, - 'exp':_weigh_exp, - 'exponential':_weigh_exp - } - + warn( + "Only integer periods are natively supported." + + "Will auto-resample to higher sampling rate" + ) + fs = int(period * freq) + + weighfoos = { + "uniform": _weigh_uniform, + "uni": _weigh_uniform, + "none": _weigh_not, + "zero": _weigh_not, + "gauss": _weigh_gaussian, + "normal": _weigh_gaussian, + "linear": _weigh_linear, + "exp": _weigh_exp, + "exponential": _weigh_exp, + } + left_weights = weighfoos[left_mode.lower()](width) right_weights = weighfoos[right_mode.lower()](width)[::-1] norm = left_weights.sum() + right_weights.sum() - - weights = np.hstack((-left_weights/norm, 1.0, -right_weights/norm)) - - midpoint = period*width - kernel = np.zeros((midpoint*2)+1) - kernel[::period] = weights + + weights = np.hstack((-left_weights / norm, 1.0, -right_weights / norm)) + + midpoint = period * width + kernel = np.zeros((midpoint * 2) + 1) + kernel[::period] = weights return kernel + # %% -def filter_1d(indata, fs:int, freq:int, kernel:ndarray): - ''' filter a one-dimensional dataset with a predefined kernel +def filter_1d(indata, fs: int, freq: int, kernel: ndarray): + """ filter a one-dimensional dataset with a predefined kernel args ---- @@ -214,44 +232,46 @@ def filter_1d(indata, fs:int, freq:int, kernel:ndarray): .. seealso:: :func:`~.filter_2d` - ''' + """ in_samples = indata.shape[0] - in_period = fs/freq - - #if sampling rate of signal and artifact are not integer divisible, + in_period = fs / freq + + # if sampling rate of signal and artifact are not integer divisible, # we have to resample the data - resample_flag = ( in_period != int(np.ceil(in_period)) ) + resample_flag = in_period != int(np.ceil(in_period)) if resample_flag: old_fs = fs period = int(np.ceil(in_period)) - fs = int(period * freq) - data = resample_by_fs(indata, up=fs, down=old_fs) + fs = int(period * freq) + data = resample_by_fs(indata, up=fs, down=old_fs) else: data = indata - period = int(in_period) - - - # if the kernel period is not matching the artifact period, + period = int(in_period) + + # if the kernel period is not matching the artifact period, # filtering would be off - kperiod, kwidth = _estimate_prms_from_kernel(kernel) + kperiod, kwidth = _estimate_prms_from_kernel(kernel) if kperiod != period: - raise ValueError('Kernel is not matching artifact frequency. ' + - 'Was the kernel correctly constructed?') + raise ValueError( + "Kernel is not matching artifact frequency. " + + "Was the kernel correctly constructed?" + ) - #------------------------------------------------------------------------- - fdata = np.convolve(data, kernel[::-1], 'same') - #------------------------------------------------------------------------- + # ------------------------------------------------------------------------- + fdata = np.convolve(data, kernel[::-1], "same") + # ------------------------------------------------------------------------- if resample_flag: filtered = resample_by_count(fdata, in_samples) - filtered = np.asanyarray(filtered) + filtered = np.asanyarray(filtered) else: - filtered = fdata - + filtered = fdata + return filtered - + + # %% -def apply_kernel(indata:ndarray, fs:int, freq:int, kernel:ndarray): - ''' filter a two-dimensional dataset with a predefined kernel +def apply_kernel(indata: ndarray, fs: int, freq: int, kernel: ndarray): + """ filter a two-dimensional dataset with a predefined kernel args ---- @@ -273,16 +293,17 @@ def apply_kernel(indata:ndarray, fs:int, freq:int, kernel:ndarray): .. seealso:: :func:`~.filter_1d` - ''' + """ filtered = np.zeros(indata.shape) - for idx, chandata in enumerate(indata): - filtered[idx,:] = filter_1d(chandata, fs, freq, kernel) - + for idx, chandata in enumerate(indata): + filtered[idx, :] = filter_1d(chandata, fs, freq, kernel) + return filtered + #%% -class CombKernel(): - '''Object-oriented comb kernel filter +class CombKernel: + """Object-oriented comb kernel filter Example to create and apply classical comb kernel:: @@ -290,11 +311,17 @@ class CombKernel(): left_mode='uniform', right_mode ='none') kernel.apply(artifacted_signal) - ''' - def __init__(self, freq:int, fs:int, width:int, - left_mode:str='uniform', - right_mode:str='uniform') -> None: - + """ + + def __init__( + self, + freq: int, + fs: int, + width: int, + left_mode: str = "uniform", + right_mode: str = "uniform", + ) -> None: + self._freq = freq self._fs = fs self._width = width @@ -303,19 +330,38 @@ def __init__(self, freq:int, fs:int, width:int, self._update_kernel() def _update_kernel(self): - self._kernel = create_kernel(self._freq, self._fs, - self._width, - self._left_mode, - self._right_mode) - - def apply(self, indata:ndarray): - return apply_kernel(indata=indata, freq=self._freq, fs=self._fs, - kernel=self._kernel) + self._kernel = create_kernel( + self._freq, + self._fs, + self._width, + self._left_mode, + self._right_mode, + ) + + def apply(self, indata: ndarray): + """ apply the kernel to a two-dimensional signal + + args + ---- + indata:ndarray + two-dimensional artifacted signal, dimensions are channel x samples - def __call__(self, indata:ndarray) -> ndarray: + returns + ------- + filtered:ndarray + two-dimensional signal with artifact removed + + """ + return apply_kernel( + indata=indata, freq=self._freq, fs=self._fs, kernel=self._kernel + ) + + def __call__(self, indata: ndarray) -> ndarray: return self.apply(indata) - + def __repr__(self): - return (f'KernelFilter({self._freq}, {self._fs}, {self._width}, ' + - f"'{self._left_mode}', '{self._right_mode}')") - + return ( + f"KernelFilter({self._freq}, {self._fs}, {self._width}, " + + f"'{self._left_mode}', '{self._right_mode}')" + ) + diff --git a/artacs/template.py b/artacs/template.py index 5ded6c9..0c63db6 100644 --- a/artacs/template.py +++ b/artacs/template.py @@ -1,137 +1,196 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -""" -Created on Wed Sep 19 13:31:21 2018 +""" Template based artifact removal + +Algorithm description +--------------------- + +:class:`~.StepwiseRemover` takes the period of the tACS artifact, and splits the timeseries into segments of that length, if necessary after resampling, to have an integer length period. It calculates the strongest principal components of this matrix (segments x period_count) and removes it until the residual power at the frequency of the tACS artifact in relation to neighbouring frequencies is below a certain threshold. To prevent discrete steps at the boundaries of the segments, this algorithm is repeated for different initial starting points. see also [1] + +[1]: Guggenberger, R., & Gharabaghi, A. (2021). Comb filters for the removal of transcranial current stimulation artifacts from single channel EEG recordings. Current Directions in Biomedical Engineering, 7(2), 383–386. https://doi.org/10.1515/cdbme-2021-2097 + + +Application +----------- + +Example:: + + remover = StepwiseRemover(fs=1000, freq=50) + remover.process(data) + -@author: rgugg """ from numpy import ndarray import numpy as np import artacs.tools as tools import logging + logger = logging.Logger(__name__) # %% -class StepwiseRemover(): +class StepwiseRemover: + """ Stepwise removal of tACS artifacts - def __init__(self, fs=1000, freq=None, period_steps=2, - epsilon=0.01, max_iterations=10, verbose=True): + args + ---- + fs: int + sampling frequency of the data + freq: float + frequency of the tACS artifact + period_steps: int + across how many periods the seed points are selected + epsilon: float + the threshold for the residual power at the frequency of the tACS artifact + max_iterations: int + how many iterations are performed + verbose: bool + sets the verbosity of the procedure + + + + """ + + def __init__( + self, + fs=1000, + freq=None, + period_steps=2, + epsilon=0.01, + max_iterations=10, + verbose=True, + ): + self.verbose = verbose self.true_fs = fs self.freq = freq if freq is not None: - self.true_period = fs/freq - self.resample_flag = (self.true_period != int(fs/freq)) + self.true_period = fs / freq + self.resample_flag = self.true_period != int(fs / freq) else: - self.true_period = None - + self.true_period = None + self.epsilon = epsilon self.max_iterations = max_iterations - self.period_steps = period_steps - + self.period_steps = period_steps + def calc_seeds(self, period): - 'derive seedpoints for starting the cutting into periods' - seeds = np.unique(np.linspace(0, period, self.period_steps+1, - dtype='int32')) - seeds = seeds[seeds!=period] + "derive seedpoints for starting the cutting into periods" + seeds = np.unique( + np.linspace(0, period, self.period_steps + 1, dtype="int32") + ) + seeds = seeds[seeds != period] return seeds - + def inbound_resample(self, indata): - 'resample so that (artifact_period* artifact_frequency) is an integer' - if self.resample_flag: + "resample so that (artifact_period* artifact_frequency) is an integer" + self.sample_count = indata.shape[0] + if self.resample_flag: period = int(np.ceil(self.true_period)) fs = int(np.ceil(period * self.freq)) - data = tools.resample_by_fs(indata, - up=fs, - down=self.true_fs, - axis=0) - self.sample_count = indata.shape[0] + data = tools.resample_by_fs( + indata, up=fs, down=self.true_fs, axis=0 + ) + else: data = indata fs = self.true_fs - period = int(self.true_period) + period = int(self.true_period) return data, period, fs def outbound_resample(self, outdata, fs): - 'reverse an earlier resampling, if it was necessary' - if self.resample_flag: - outdata = tools.resample_by_count(outdata, - self.sample_count, - axis=0) + "reverse an earlier resampling, if it was necessary" + if self.resample_flag: + outdata = tools.resample_by_count( + outdata, self.sample_count, axis=0 + ) return outdata def prepare_data(self, indata): - 'resample and derive seedpoints' + "resample and derive seedpoints" valid_data = indata[np.invert(np.isnan(indata))] data, period, fs = self.inbound_resample(valid_data) seeds = self.calc_seeds(period) - return data, period, fs, seeds - - def __call__(self, indata:ndarray) -> ndarray: + return data, period, fs, seeds + + def __call__(self, indata: ndarray) -> ndarray: return self.process(indata) - - def process(self, indata:ndarray): - 'process all channels of a dataset' + + def process(self, indata: ndarray): + """process all channels of a dataset + + args + ---- + indata: ndarray + the two-dimensional data to be processed (channels x samples) + + returns + ------- + outdata: ndarray + the filtered data + + """ if self.true_period is None: - print('Invalid period length, skipping artifact removal') + print("Invalid period length, skipping artifact removal") return indata - + if len(indata.shape) == 1: num_channels, num_samples = 1, indata.shape[0] indata = np.atleast_2d(indata) elif len(indata.shape) == 2: num_channels, num_samples = indata.shape - else: - raise ValueError('Unspecified dimensionality of the dataset') + else: + raise ValueError("Unspecified dimensionality of the dataset") outdata = np.empty((indata.shape)) outdata.fill(np.nan) if self.verbose: - print('[',end='') - for chan_idx, chan_data in enumerate(indata): - outdata[chan_idx,:] = self.process_channel(chan_data) + print("[", end="") + for chan_idx, chan_data in enumerate(indata): + outdata[chan_idx, :] = self.process_channel(chan_data) if self.verbose: - print('.',end='') + print(".", end="") if self.verbose: - print(']',end='\n') + print("]", end="\n") return np.squeeze(outdata) - - def process_channel(self, indata:ndarray) -> ndarray: - 'process a single channels of data' + + def process_channel(self, indata: ndarray) -> ndarray: + "process a single channels of data" if self.true_period is None: - print('Invalid period length, skipping artifact removal') + print("Invalid period length, skipping artifact removal") return indata - - data, period, fs, seeds = self.prepare_data(indata) - outdata = np.empty((data.shape[0], seeds.shape[0]+1)) + + data, period, fs, seeds = self.prepare_data(indata) + outdata = np.empty((data.shape[0], seeds.shape[0] + 1)) outdata.fill(np.nan) - - for seed_idx, seed in enumerate(seeds): + + for seed_idx, seed in enumerate(seeds): idx, fdata = self._process(data, period, fs, seed) - outdata[idx, seed_idx] = fdata + outdata[idx, seed_idx] = fdata - missing_part = idx[-1]+period != outdata.shape[0] - if missing_part: #perform filtering in time-reversed data + missing_part = idx[-1] + period != outdata.shape[0] + if missing_part: # perform filtering in time-reversed data idx, fdata = self._process(data[::-1], period, fs, seed=0) - outdata[outdata.shape[0]-idx[-1]-1:, -1] = fdata[::-1] - + outdata[outdata.shape[0] - idx[-1] - 1 :, -1] = fdata[::-1] + outdata = np.nanmean(outdata, axis=1) - outdata = self.outbound_resample(outdata, fs) - + outdata = self.outbound_resample(outdata, fs) + return outdata - def _process(self, data:ndarray, period:int, fs:int, seed:int): + def _process(self, data: ndarray, period: int, fs: int, seed: int): converged = False iteration = 0 fdata = data.copy() - while not converged: - period_data, put_where = tools.signal2periods(fdata, - period, offset=seed) + while not converged: + period_data, put_where = tools.signal2periods( + fdata, period, offset=seed + ) component, score, l = tools.pca_largest(period_data) - template = tools.comp2trace(component, score, kind='cubic') - amplitude = tools.estimate_artifact_peakiness(template, - fs, self.freq) + template = tools.comp2trace(component, score, kind="cubic") + amplitude = tools.estimate_artifact_peakiness( + template, fs, self.freq + ) iteration += 1 if amplitude < self.epsilon: - converged = True + converged = True else: - fdata[put_where] -= template + fdata[put_where] -= template return put_where, fdata[put_where] diff --git a/doc/build/doctrees/_autosummary/artacs.kernel.doctree b/doc/build/doctrees/_autosummary/artacs.kernel.doctree deleted file mode 100644 index ba931ca..0000000 --- a/doc/build/doctrees/_autosummary/artacs.kernel.doctree +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:13c423d73b17f05634cff9d31d75ad854cf174666ea83bf7fdd469d025c6bbb6 -size 38835 diff --git a/doc/build/doctrees/environment.pickle b/doc/build/doctrees/environment.pickle deleted file mode 100644 index 17adc43..0000000 --- a/doc/build/doctrees/environment.pickle +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ca0f3888a1441ea8055583e99998564c6d3fcfba2ea5284a5d54631e9e601189 -size 16332 diff --git a/doc/build/doctrees/index.doctree b/doc/build/doctrees/index.doctree deleted file mode 100644 index 497fc44..0000000 --- a/doc/build/doctrees/index.doctree +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e19dd2a24996e1844f5a117c07a123bc8a5e550383b3c9d8f66cea9021743dd5 -size 6734 diff --git a/doc/build/html/.buildinfo b/doc/build/html/.buildinfo deleted file mode 100644 index 2e4467b..0000000 --- a/doc/build/html/.buildinfo +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:74e4e7b76bcc78eee9d4acf5d1929e9ab8564ed86a20cf61aab6ac204b50035d -size 230 diff --git a/doc/build/html/_autosummary/artacs.kernel.html b/doc/build/html/_autosummary/artacs.kernel.html deleted file mode 100644 index ef7c790..0000000 --- a/doc/build/html/_autosummary/artacs.kernel.html +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c2d3379bd73d069b1db4fa5ee91227faeae2c54c86b1b0c34d23b1e3752a1e8c -size 16542 diff --git a/doc/build/html/_modules/artacs/kernel.html b/doc/build/html/_modules/artacs/kernel.html deleted file mode 100644 index e364ab4..0000000 --- a/doc/build/html/_modules/artacs/kernel.html +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e003985345d8d5fa48688d88dab0339045a0c289643af0ba0c4af701d9a5c68d -size 36354 diff --git a/doc/build/html/_modules/index.html b/doc/build/html/_modules/index.html deleted file mode 100644 index 1cf5d94..0000000 --- a/doc/build/html/_modules/index.html +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:46646aaafe58442eaff0d935171e6ff06280ba70c04d15f2a332161046f5cb1e -size 4135 diff --git a/doc/build/html/_sources/_autosummary/artacs.kernel.rst.txt b/doc/build/html/_sources/_autosummary/artacs.kernel.rst.txt deleted file mode 100644 index 50df1db..0000000 --- a/doc/build/html/_sources/_autosummary/artacs.kernel.rst.txt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fcdf42145ec4cf3e0f2f64d15b8e078310af4a53704885328507418eb8186aee -size 92 diff --git a/doc/build/html/_sources/index.rst.txt b/doc/build/html/_sources/index.rst.txt deleted file mode 100644 index bed574c..0000000 --- a/doc/build/html/_sources/index.rst.txt +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ac0135809a81430296ea399736de839d1906080a5e4faa1fbc70d4eced0a3411 -size 582 diff --git a/doc/build/html/_static/ajax-loader.gif b/doc/build/html/_static/ajax-loader.gif deleted file mode 100644 index 812a8be..0000000 --- a/doc/build/html/_static/ajax-loader.gif +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5d045fd991ddf2b208dd9bf39a591f50e6ec793416e2867f54e8c6c7e89b68c2 -size 673 diff --git a/doc/build/html/_static/basic.css b/doc/build/html/_static/basic.css deleted file mode 100644 index 1edffa0..0000000 --- a/doc/build/html/_static/basic.css +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b61fc4383784ca3ff8589a1bb48d19d06fddc78d6120cbc9ad31f275f62f4cce -size 10716 diff --git a/doc/build/html/_static/comment-bright.png b/doc/build/html/_static/comment-bright.png deleted file mode 100644 index b644c22..0000000 --- a/doc/build/html/_static/comment-bright.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0737b92f8825f5ed0740482819f3fba7826297908bbd44ff00b64ee95d262d60 -size 756 diff --git a/doc/build/html/_static/comment-close.png b/doc/build/html/_static/comment-close.png deleted file mode 100644 index 2b66c95..0000000 --- a/doc/build/html/_static/comment-close.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:866319c7cf09c3d5b2926ea9d9f068801c8ee0724dac66604b03ac50b1829577 -size 829 diff --git a/doc/build/html/_static/comment.png b/doc/build/html/_static/comment.png deleted file mode 100644 index 9bd8d0d..0000000 --- a/doc/build/html/_static/comment.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fb8b0b215a51fc05bc152a12ab32d44cda758721c5df53f2aeab1b1e3490aa5 -size 641 diff --git a/doc/build/html/_static/css/badge_only.css b/doc/build/html/_static/css/badge_only.css deleted file mode 100644 index 5e44d9c..0000000 --- a/doc/build/html/_static/css/badge_only.css +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8a2fe21d0363ef43f60329e676bc512f3f47fd4683f17c0782deea2da792304a -size 3358 diff --git a/doc/build/html/_static/css/theme.css b/doc/build/html/_static/css/theme.css deleted file mode 100644 index 6cf65eb..0000000 --- a/doc/build/html/_static/css/theme.css +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:831fdd7586b603decc9740baf73f97a1d28d86f3f0426e904a6db6758a0b8d83 -size 116310 diff --git a/doc/build/html/_static/doctools.js b/doc/build/html/_static/doctools.js deleted file mode 100644 index df9e7a3..0000000 --- a/doc/build/html/_static/doctools.js +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ba5080dd83bfbc09c8440ecc3e163b7352073f7428a92facb9dfcd04ba29188b -size 9224 diff --git a/doc/build/html/_static/documentation_options.js b/doc/build/html/_static/documentation_options.js deleted file mode 100644 index 7abd4a6..0000000 --- a/doc/build/html/_static/documentation_options.js +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f742cc7406ddc9291359461f4615b4b1869ad20ba1100871149ca6e58f767f53 -size 198 diff --git a/doc/build/html/_static/down-pressed.png b/doc/build/html/_static/down-pressed.png deleted file mode 100644 index 0f96732..0000000 --- a/doc/build/html/_static/down-pressed.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c89ca40639d0bb71502306afdbc8646f6ef362b79c54a8f9211aa290ad8b3635 -size 222 diff --git a/doc/build/html/_static/down.png b/doc/build/html/_static/down.png deleted file mode 100644 index 1f542e2..0000000 --- a/doc/build/html/_static/down.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:75fc30ab04aa494f8ab239fba636663b950ccff763bd3b95a3c214ee2344ec89 -size 202 diff --git a/doc/build/html/_static/file.png b/doc/build/html/_static/file.png deleted file mode 100644 index 3852249..0000000 --- a/doc/build/html/_static/file.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5c4bc9a16aebf38c4b950f59b8e501ca36495328cb9eb622218bce9064a35e3e -size 286 diff --git a/doc/build/html/_static/fonts/Lato/lato-bold.eot b/doc/build/html/_static/fonts/Lato/lato-bold.eot deleted file mode 100644 index 362c87e..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-bold.eot +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b91fc1ca55df440dc11354b32a39b45db663d24bb17b16dcb2e706330955b0d1 -size 256056 diff --git a/doc/build/html/_static/fonts/Lato/lato-bold.ttf b/doc/build/html/_static/fonts/Lato/lato-bold.ttf deleted file mode 100644 index f7e55a9..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-bold.ttf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f71f833c099f450606f8107b83ef208ae918c0ea00779466d45e9be96b0bc7cc -size 600856 diff --git a/doc/build/html/_static/fonts/Lato/lato-bold.woff b/doc/build/html/_static/fonts/Lato/lato-bold.woff deleted file mode 100644 index 3272a2d..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-bold.woff +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0e56b17d142eb366c8007031d14e34da48c70b4a9d9a0ca492e696a7bae45e1e -size 309728 diff --git a/doc/build/html/_static/fonts/Lato/lato-bold.woff2 b/doc/build/html/_static/fonts/Lato/lato-bold.woff2 deleted file mode 100644 index 6895d4d..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-bold.woff2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ae88fc0d7a961832f809527d30bd3983a6866d42f66a56ade23f543681594db6 -size 184912 diff --git a/doc/build/html/_static/fonts/Lato/lato-bolditalic.eot b/doc/build/html/_static/fonts/Lato/lato-bolditalic.eot deleted file mode 100644 index 47a76d3..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-bolditalic.eot +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b3d585879a02f48c5d43d8f91d06b167e367a31934bb3b8147c0a90b5ca32bfc -size 266158 diff --git a/doc/build/html/_static/fonts/Lato/lato-bolditalic.ttf b/doc/build/html/_static/fonts/Lato/lato-bolditalic.ttf deleted file mode 100644 index 586f201..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-bolditalic.ttf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f98d040631714eabffd0ffb747576674fa78c2910f6d9e3dc0c58481d03c1898 -size 622572 diff --git a/doc/build/html/_static/fonts/Lato/lato-bolditalic.woff b/doc/build/html/_static/fonts/Lato/lato-bolditalic.woff deleted file mode 100644 index f27a031..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-bolditalic.woff +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:980c8592e5488df256192c999e92db8fd302db8cd8909b7fa266a684e37e45f8 -size 323344 diff --git a/doc/build/html/_static/fonts/Lato/lato-bolditalic.woff2 b/doc/build/html/_static/fonts/Lato/lato-bolditalic.woff2 deleted file mode 100644 index f114414..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-bolditalic.woff2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c0916a33340d063f7b05679e08031e729d1888444706f04804705da5966d895d -size 193308 diff --git a/doc/build/html/_static/fonts/Lato/lato-italic.eot b/doc/build/html/_static/fonts/Lato/lato-italic.eot deleted file mode 100644 index ab0d781..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-italic.eot +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:bc24dbe04f5b2415678f978e7e2f630cc6610670d684e088e73ad29c439eafe3 -size 268604 diff --git a/doc/build/html/_static/fonts/Lato/lato-italic.ttf b/doc/build/html/_static/fonts/Lato/lato-italic.ttf deleted file mode 100644 index 24c6632..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-italic.ttf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:12d825af88eafea1ce3aa469f83c03acaecd0d03f690f409c8643529f1205b4f -size 639388 diff --git a/doc/build/html/_static/fonts/Lato/lato-italic.woff b/doc/build/html/_static/fonts/Lato/lato-italic.woff deleted file mode 100644 index bd5f9dd..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-italic.woff +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:26318a1467a5e5caf10b04cfa942d079632560cd7a29cec565fd1dc9f7ec5081 -size 328412 diff --git a/doc/build/html/_static/fonts/Lato/lato-italic.woff2 b/doc/build/html/_static/fonts/Lato/lato-italic.woff2 deleted file mode 100644 index 400eaf7..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-italic.woff2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4465765f2f6eddcdad34ffd7cab559e56bc0e75e45e192f85e9562b0771481dc -size 195704 diff --git a/doc/build/html/_static/fonts/Lato/lato-regular.eot b/doc/build/html/_static/fonts/Lato/lato-regular.eot deleted file mode 100644 index 419d993..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-regular.eot +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e735410675eacc363b257112f39eb819a854b03077d7b1f0caa6e7660ffbd8b3 -size 253461 diff --git a/doc/build/html/_static/fonts/Lato/lato-regular.ttf b/doc/build/html/_static/fonts/Lato/lato-regular.ttf deleted file mode 100644 index a558b22..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-regular.ttf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:089ab6d4a57e0e6c4dd3b681b6fd50a5184f1b902429d35e1227e52d6ccad1bd -size 607720 diff --git a/doc/build/html/_static/fonts/Lato/lato-regular.woff b/doc/build/html/_static/fonts/Lato/lato-regular.woff deleted file mode 100644 index df48c60..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-regular.woff +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5b9025dda4d7688e3311b0c17eddc501133b807def33effaef6593843cf5416e -size 309192 diff --git a/doc/build/html/_static/fonts/Lato/lato-regular.woff2 b/doc/build/html/_static/fonts/Lato/lato-regular.woff2 deleted file mode 100644 index 68fe677..0000000 --- a/doc/build/html/_static/fonts/Lato/lato-regular.woff2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:983b0caf336e8542214fc17019a4fc5e0360864b92806ca14d55c1fc1c2c5a0f -size 182708 diff --git a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot b/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot deleted file mode 100644 index 4709fb9..0000000 --- a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4438991a12ff951cc8d0e83348ec06d9f910591b1b014c476e9595d4da099e48 -size 79520 diff --git a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf b/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf deleted file mode 100644 index e89d6f4..0000000 --- a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ba12d2eab1fa765b6b05398fa7e047dd76293f0c051ce57a8f7b0c591c14d42b -size 170616 diff --git a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff b/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff deleted file mode 100644 index 0dcb5cc..0000000 --- a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9fec87cadbe2413b255f1ec577573a83f1ca2e1c37aa023dbebcd3a7b864636a -size 87624 diff --git a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 b/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 deleted file mode 100644 index e85930b..0000000 --- a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1a0c024dd1a267c52d5575469ffe8570d1e84164de7d393cf3414bafd17d7a0c -size 67312 diff --git a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot b/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot deleted file mode 100644 index b13f119..0000000 --- a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b3809b71d417c6c225e77a55880aa7915b4e4b4f77a5e2d243f3563731e7f55c -size 78331 diff --git a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf b/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf deleted file mode 100644 index b5a8cb9..0000000 --- a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:13aa5f54c6f2fa2e388fe0e675cdbcc6a81f6270a8bf9c03a5df8af9cb022810 -size 169064 diff --git a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff b/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff deleted file mode 100644 index d942ccb..0000000 --- a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9f32630e2c0c5135bf1e86e36cb65b3932e4410644235bc2bd995e9c7f6ff117 -size 86288 diff --git a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 b/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 deleted file mode 100644 index 5967195..0000000 --- a/doc/build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:874e42222856d7af03b3f438d21d923a4280d47fe67c48510e2174a1579795ef -size 66444 diff --git a/doc/build/html/_static/fonts/fontawesome-webfont.eot b/doc/build/html/_static/fonts/fontawesome-webfont.eot deleted file mode 100644 index 67601ff..0000000 --- a/doc/build/html/_static/fonts/fontawesome-webfont.eot +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979 -size 165742 diff --git a/doc/build/html/_static/fonts/fontawesome-webfont.svg b/doc/build/html/_static/fonts/fontawesome-webfont.svg deleted file mode 100644 index dfeb3d6..0000000 --- a/doc/build/html/_static/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4 -size 444379 diff --git a/doc/build/html/_static/fonts/fontawesome-webfont.ttf b/doc/build/html/_static/fonts/fontawesome-webfont.ttf deleted file mode 100644 index cc52454..0000000 --- a/doc/build/html/_static/fonts/fontawesome-webfont.ttf +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8 -size 165548 diff --git a/doc/build/html/_static/fonts/fontawesome-webfont.woff b/doc/build/html/_static/fonts/fontawesome-webfont.woff deleted file mode 100644 index a9d0dca..0000000 --- a/doc/build/html/_static/fonts/fontawesome-webfont.woff +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07 -size 98024 diff --git a/doc/build/html/_static/fonts/fontawesome-webfont.woff2 b/doc/build/html/_static/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 1da78e1..0000000 --- a/doc/build/html/_static/fonts/fontawesome-webfont.woff2 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe -size 77160 diff --git a/doc/build/html/_static/img/recovery_ecg.png b/doc/build/html/_static/img/recovery_ecg.png deleted file mode 100644 index 6a03b2a..0000000 --- a/doc/build/html/_static/img/recovery_ecg.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:26fd7eba275e41e3a38bed0554cb0c21f2813b399a25519cc1c1831a1c12c485 -size 50331 diff --git a/doc/build/html/_static/img/upper_limb_ecg.jpg b/doc/build/html/_static/img/upper_limb_ecg.jpg deleted file mode 100644 index 655d419..0000000 --- a/doc/build/html/_static/img/upper_limb_ecg.jpg +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:7da8b6f7b6b5ecb0a41156788ea22f36d4ee2137b84f6d0ace9822924180d58a -size 46134 diff --git a/doc/build/html/_static/jquery-3.2.1.js b/doc/build/html/_static/jquery-3.2.1.js deleted file mode 100644 index 44bd61e..0000000 --- a/doc/build/html/_static/jquery-3.2.1.js +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:0d9027289ffa5d9f6c8b4e0782bb31bbff2cef5ee3708ccbcb7a22df9128bb21 -size 268039 diff --git a/doc/build/html/_static/jquery.js b/doc/build/html/_static/jquery.js deleted file mode 100644 index 50ff8f6..0000000 --- a/doc/build/html/_static/jquery.js +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:87083882cc6015984eb0411a99d3981817f5dc5c90ba24f0940420c5548d82de -size 86659 diff --git a/doc/build/html/_static/js/modernizr.min.js b/doc/build/html/_static/js/modernizr.min.js deleted file mode 100644 index 5a25c8a..0000000 --- a/doc/build/html/_static/js/modernizr.min.js +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cf25ec18f223f4c51ce1128a42e644cdc2244d88f89d1a51440d9dbe51f4efe8 -size 15414 diff --git a/doc/build/html/_static/js/theme.js b/doc/build/html/_static/js/theme.js deleted file mode 100644 index cc3e788..0000000 --- a/doc/build/html/_static/js/theme.js +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c132ba71881f7d6f103565eb555fdcf258af9495ead1b82aad578bf10079677d -size 4400 diff --git a/doc/build/html/_static/minus.png b/doc/build/html/_static/minus.png deleted file mode 100644 index b34a51a..0000000 --- a/doc/build/html/_static/minus.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:47e7fc50db3699f1ca41ce9a2ffa202c00c5d1d5180c55f62ba859b1bd6cc008 -size 90 diff --git a/doc/build/html/_static/plus.png b/doc/build/html/_static/plus.png deleted file mode 100644 index ffaf9e0..0000000 --- a/doc/build/html/_static/plus.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:54115199b96a130cba02147c47c0deb43dcc9b9f08b5162bba8642b34980ac63 -size 90 diff --git a/doc/build/html/_static/pygments.css b/doc/build/html/_static/pygments.css deleted file mode 100644 index 1fb9843..0000000 --- a/doc/build/html/_static/pygments.css +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c67b5260b50a0f434e9b26585479ce67ab2184adc7b31c26d665642d3512835f -size 4395 diff --git a/doc/build/html/_static/searchtools.js b/doc/build/html/_static/searchtools.js deleted file mode 100644 index ca86b61..0000000 --- a/doc/build/html/_static/searchtools.js +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:e8d039d87d8f443d02abb76df25715de53a329a7a35cb58d4767c08a574fbe00 -size 25449 diff --git a/doc/build/html/_static/underscore-1.3.1.js b/doc/build/html/_static/underscore-1.3.1.js deleted file mode 100644 index 1e15cfc..0000000 --- a/doc/build/html/_static/underscore-1.3.1.js +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:f808f0aa32fbe90fb9c9c846917faff3fdd4e236c284b76c02dd33753dc90177 -size 35168 diff --git a/doc/build/html/_static/underscore.js b/doc/build/html/_static/underscore.js deleted file mode 100644 index 0d6facb..0000000 --- a/doc/build/html/_static/underscore.js +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:42d8fad13bc28fc726775196ec9ab953febf9bde175c5845128361c953fa17f4 -size 12140 diff --git a/doc/build/html/_static/up-pressed.png b/doc/build/html/_static/up-pressed.png deleted file mode 100644 index 251dc02..0000000 --- a/doc/build/html/_static/up-pressed.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cfe678a4446900f4081ab8d74ef3d1f8b1002edbf8cae3db292fcca0637310ed -size 214 diff --git a/doc/build/html/_static/up.png b/doc/build/html/_static/up.png deleted file mode 100644 index cb37346..0000000 --- a/doc/build/html/_static/up.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:108f280badfe5ec5168738c4f70a59bc6ea9d1e9243ff2b951386fb668e93502 -size 203 diff --git a/doc/build/html/_static/websupport.js b/doc/build/html/_static/websupport.js deleted file mode 100644 index 664ba72..0000000 --- a/doc/build/html/_static/websupport.js +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:3e61ad44de4625bdd7aa3b1ac8ddad355c919de8a23bd16fb36053901ff23cb9 -size 25355 diff --git a/doc/build/html/genindex.html b/doc/build/html/genindex.html deleted file mode 100644 index 4417a33..0000000 --- a/doc/build/html/genindex.html +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:5fd3d53b18fbf2a072100cfbb7333b3f9000891e60836c0db9ef4e8f9e905935 -size 5711 diff --git a/doc/build/html/index.html b/doc/build/html/index.html deleted file mode 100644 index 3097197..0000000 --- a/doc/build/html/index.html +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:13d811252a6b688acb9442681ced22e67434dfc0d3db47da3c9a328fd741ab3f -size 5880 diff --git a/doc/build/html/objects.inv b/doc/build/html/objects.inv deleted file mode 100644 index bf8d5e5..0000000 --- a/doc/build/html/objects.inv +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:936bd18bc460c71d384a49536f70825bf5c606ab73a1907f922784ca9302faf7 -size 363 diff --git a/doc/build/html/py-modindex.html b/doc/build/html/py-modindex.html deleted file mode 100644 index a779370..0000000 --- a/doc/build/html/py-modindex.html +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:a786763303a5b0739b577e375434c7c967ff102d1257e053188d39718c917a82 -size 4745 diff --git a/doc/build/html/search.html b/doc/build/html/search.html deleted file mode 100644 index 18589a0..0000000 --- a/doc/build/html/search.html +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1891e1c77c6e28a8538376b97083a1759479ba813e7cf036617803a8f3f5f313 -size 4440 diff --git a/doc/build/html/searchindex.js b/doc/build/html/searchindex.js deleted file mode 100644 index 35704d7..0000000 --- a/doc/build/html/searchindex.js +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fb4e316c9e7b077a9caadc3d68cdc53039b52cc3b8f2a6fddd571468a3b3697b -size 1959 diff --git a/doc/source/api.rst b/doc/source/api.rst new file mode 100644 index 0000000..625fed3 --- /dev/null +++ b/doc/source/api.rst @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2969f305853f232f59199985633c3ec41280e3a106efdfdefef7bebb5306202f +size 322 diff --git a/doc/source/examples.rst b/doc/source/examples.rst new file mode 100644 index 0000000..d830013 --- /dev/null +++ b/doc/source/examples.rst @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9240291cf63ee6262779573454fc29dc4adca86c562fac0ab44b8db4e655156 +size 1317 diff --git a/doc/source/index.rst b/doc/source/index.rst index bed574c..e80abfa 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac0135809a81430296ea399736de839d1906080a5e4faa1fbc70d4eced0a3411 -size 582 +oid sha256:86e8e562003c8fe0877fd81730844829dbd20893fbf85a2882d9dda230843d18 +size 601 diff --git a/example.py b/example.py new file mode 100644 index 0000000..8162b04 --- /dev/null +++ b/example.py @@ -0,0 +1,28 @@ +from artacs import CombKernel +import numpy as np +import time + +fs = 1000 +duration = 1 +t = np.linspace(0, duration, duration * fs) +data = np.atleast_2d(np.sin(2 * 10 * np.pi * t)) + +ck = CombKernel( + freq=10, fs=1000, width=1, left_mode="uniform", right_mode="none" +) + +T = [] +for i in range(10_000): + t0 = time.time_ns() + out = ck.apply(data) + T.append((time.time_ns() - t0) / 1000) +print( + f"99% CI of calculation time for 1s data is between {np.percentile(T, 0.5):3.2f} to {np.percentile(T, 99.5):3.2f} µs" +) +import matplotlib.pyplot as plt + +plt.plot(data.T, label="Raw") +plt.plot(out.T, label="Filtered") +plt.legend() +plt.show() + diff --git a/doc/build/html/.nojekyll b/test/__init__.py similarity index 100% rename from doc/build/html/.nojekyll rename to test/__init__.py diff --git a/test/test.py b/test/test.py deleted file mode 100644 index e5f54b1..0000000 --- a/test/test.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -'''Test module for pyArtacs - - -''' -from artacs.kernel import create_kernel, _estimate_prms_from_kernel, filter_1d, apply_kernel -from artacs.kernel import CombKernel -from artacs.template import StepwiseRemover -import numpy as np -#%% -def test_kernel(): - freq = 10 - fs = 1000 - width = 5 - period = int(np.ceil(fs/freq)) - kernel = create_kernel(freq, fs, width) - assert np.isclose(kernel.sum(), 0.0) - assert kernel.shape[0] == 1001 - assert(_estimate_prms_from_kernel(kernel) == (period, width)) - - kernel = create_kernel(freq, fs, width, - left_mode='uniform',right_mode ='None') - assert np.isclose(kernel.sum(), 0.0) - assert kernel.shape[0] == 1001 - assert(_estimate_prms_from_kernel(kernel) == (period, width)) - assert np.all(np.isclose(kernel[::period], - np.array([-0.2, -0.2, -0.2, -0.2, -0.2, 1., - -0. , -0. , -0. , -0. , -0. ]))) - - kernel = create_kernel(freq, fs, width, - left_mode='gauss',right_mode ='exp') - assert np.isclose(kernel.sum(), 0.0) - assert kernel.shape[0] == 1001 - assert(_estimate_prms_from_kernel(kernel) == (period, width)) - assert np.all(np.isclose(kernel[::period], - np.array([-1.59837446e-05, -8.72682888e-04, - -1.75283044e-02, -1.29517624e-01, - -3.52065405e-01, 1.00000000e+00, - -3.18204323e-01, -1.17060829e-01, - -4.30642722e-02, -1.58424604e-02, - -5.82811548e-03]))) - - kernel = create_kernel(freq, fs, width, - left_mode='linear',right_mode ='uniform') - assert np.isclose(kernel.sum(), 0.0) - assert kernel.shape[0] == 1001 - assert(_estimate_prms_from_kernel(kernel) == (period, width)) - assert np.all(np.isclose(kernel[::period], - np.array([-0.03333333, -0.06666667, -0.1, - -0.13333333, -0.16666667, 1. , -0.1, - -0.1, -0.1, -0.1,-0.1]))) - - - # test directionality of kernel - fs = 1000 - freq = 10 - period = int(np.ceil(fs/freq)) - duration_in_s = 2 - t = np.linspace(1/fs, duration_in_s, num=fs*duration_in_s) - data = np.zeros(np.shape(t)) - data[data.shape[0]//2] = 1 - kernel = create_kernel(freq, fs, 1, - left_mode='uniform', right_mode ='none') - filtered = filter_1d(data, fs, freq, kernel) - assert np.where(filtered==1.0)[0][0] == 1000 - assert np.where(filtered==-1.0)[0][0] == 1100 - - - # test kernel removes sine perfectly - fs = 1000 - freq = 10 - period = int(np.ceil(fs/freq)) - duration_in_s = 2 - t = np.linspace(1/fs, duration_in_s, num=fs*duration_in_s) - data = np.sin(2*np.pi*freq*t) - kernel = create_kernel(freq, fs, 1, - left_mode='uniform', right_mode ='none') - filtered = filter_1d(data, fs, freq, kernel) - assert np.all(np.isclose(filtered[period:], 0, 1e-10)) - - # test kernel removes sine somewhat well when fs mismatch - fs = 1000 - freq = 15 - for freq in range(10, 21, 1): - period = int(np.ceil(fs/freq)) - kernel = create_kernel(freq, fs, 1, - left_mode='uniform', right_mode ='none') - t = np.linspace(1/fs, duration_in_s, num=fs*duration_in_s) - data = np.sin(2*np.pi*freq*t) - filtered = filter_1d(data, fs, freq, kernel) - print('{:3.0f} '.format(freq),end='') - print(np.max(np.abs(filtered[period*2:]))) - assert np.all(np.isclose(filtered[period*2:], 0, atol=1e-04)) - - # test multi-channel filter - # we only check for everything after the first period to account for the - # settle-in duration of the one-step comb filter - fs = 1000 - freq = 10 - period = int(np.ceil(fs/freq)) - duration_in_s = 2 - t = np.linspace(1/fs, duration_in_s, num=fs*duration_in_s) - data = np.sin(2*np.pi*freq*t) - data = np.vstack((data, data)) - kernel = create_kernel(freq, fs, 1, - left_mode='uniform', right_mode ='none') - filtered = apply_kernel(data, fs, freq, kernel) - for chan in filtered: - assert np.all(np.isclose(chan[period:], 0, 1e-10)) - - - k = CombKernel(freq=freq, fs=fs, width=1, - left_mode='uniform', right_mode ='none') - duration_in_s = 2 - t = np.linspace(1/fs, duration_in_s, num=fs*duration_in_s) - data = np.sin(2*np.pi*freq*t) - data = np.vstack((data, data)) - filtered = k(data) - for chan in filtered: - assert np.all(np.isclose(chan[period:], 0, 1e-10)) - - - s = StepwiseRemover(fs=fs, freq=freq) - duration_in_s = 2 - t = np.linspace(1/fs, duration_in_s, num=fs*duration_in_s) - data = np.sin(2*np.pi*freq*t) - data = np.vstack((data, data)) - filtered = s(data) - for chan in filtered: - assert np.all(np.isclose(chan[:], 0, 1e-10)) - - fs = 5000 - duration_in_s = 2 - for freq in range(10, 21, 1): - s = StepwiseRemover(fs=fs, freq=freq, period_steps=10) - t = np.linspace(1/fs, duration_in_s, num=fs*duration_in_s) - nse = np.random.randn(t.shape[0]) - data = 1000*np.sin(2*np.pi*freq*t) + nse - filtered = s(data) - print('{:3.0f} '.format(freq),end='') - r2 = np.square(np.corrcoef(filtered, nse)[0,1]) - print(np.max(np.abs(filtered)), r2) - assert np.all(r2>0.7071) - - - print('Test successful') - -# %% -if __name__ == '__main__': - test_kernel() - diff --git a/test/test_kernel.py b/test/test_kernel.py new file mode 100644 index 0000000..3e18019 --- /dev/null +++ b/test/test_kernel.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +"""Test module for pyArtacs + + +""" +from artacs.kernel import ( + create_kernel, + _estimate_prms_from_kernel, + filter_1d, + apply_kernel, +) +from artacs.kernel import CombKernel +from artacs.template import StepwiseRemover +import numpy as np + +#%% +def test_kernel(): + freq = 10 + fs = 1000 + width = 5 + period = int(np.ceil(fs / freq)) + kernel = create_kernel(freq, fs, width) + assert np.isclose(kernel.sum(), 0.0) + assert kernel.shape[0] == 1001 + assert _estimate_prms_from_kernel(kernel) == (period, width) + + kernel = create_kernel(freq, fs, width, left_mode="uniform", right_mode="None") + assert np.isclose(kernel.sum(), 0.0) + assert kernel.shape[0] == 1001 + assert _estimate_prms_from_kernel(kernel) == (period, width) + assert np.all( + np.isclose( + kernel[::period], + np.array([-0.2, -0.2, -0.2, -0.2, -0.2, 1.0, -0.0, -0.0, -0.0, -0.0, -0.0]), + ) + ) + + kernel = create_kernel(freq, fs, width, left_mode="gauss", right_mode="exp") + assert np.isclose(kernel.sum(), 0.0) + assert kernel.shape[0] == 1001 + assert _estimate_prms_from_kernel(kernel) == (period, width) + assert np.all( + np.isclose( + kernel[::period], + np.array( + [ + -1.59837446e-05, + -8.72682888e-04, + -1.75283044e-02, + -1.29517624e-01, + -3.52065405e-01, + 1.00000000e00, + -3.18204323e-01, + -1.17060829e-01, + -4.30642722e-02, + -1.58424604e-02, + -5.82811548e-03, + ] + ), + ) + ) + + kernel = create_kernel(freq, fs, width, left_mode="linear", right_mode="uniform") + assert np.isclose(kernel.sum(), 0.0) + assert kernel.shape[0] == 1001 + assert _estimate_prms_from_kernel(kernel) == (period, width) + assert np.all( + np.isclose( + kernel[::period], + np.array( + [ + -0.03333333, + -0.06666667, + -0.1, + -0.13333333, + -0.16666667, + 1.0, + -0.1, + -0.1, + -0.1, + -0.1, + -0.1, + ] + ), + ) + ) + + # test directionality of kernel + fs = 1000 + freq = 10 + period = int(np.ceil(fs / freq)) + duration_in_s = 2 + t = np.linspace(1 / fs, duration_in_s, num=fs * duration_in_s) + data = np.zeros(np.shape(t)) + data[data.shape[0] // 2] = 1 + kernel = create_kernel(freq, fs, 1, left_mode="uniform", right_mode="none") + filtered = filter_1d(data, fs, freq, kernel) + assert np.where(filtered == 1.0)[0][0] == 1000 + assert np.where(filtered == -1.0)[0][0] == 1100 + + # test kernel removes sine perfectly + fs = 1000 + freq = 10 + period = int(np.ceil(fs / freq)) + duration_in_s = 2 + t = np.linspace(1 / fs, duration_in_s, num=fs * duration_in_s) + data = np.sin(2 * np.pi * freq * t) + kernel = create_kernel(freq, fs, 1, left_mode="uniform", right_mode="none") + filtered = filter_1d(data, fs, freq, kernel) + assert np.all(np.isclose(filtered[period:], 0, 1e-10)) + + # test kernel removes sine somewhat well when fs mismatch + fs = 1000 + freq = 15 + for freq in range(10, 21, 1): + period = int(np.ceil(fs / freq)) + kernel = create_kernel(freq, fs, 1, left_mode="uniform", right_mode="none") + t = np.linspace(1 / fs, duration_in_s, num=fs * duration_in_s) + data = np.sin(2 * np.pi * freq * t) + filtered = filter_1d(data, fs, freq, kernel) + print("{:3.0f} ".format(freq), end="") + print(np.max(np.abs(filtered[period * 2 :]))) + assert np.all(np.isclose(filtered[period * 2 :], 0, atol=1e-04)) + + # test multi-channel filter + # we only check for everything after the first period to account for the + # settle-in duration of the one-step comb filter + fs = 1000 + freq = 10 + period = int(np.ceil(fs / freq)) + duration_in_s = 2 + t = np.linspace(1 / fs, duration_in_s, num=fs * duration_in_s) + data = np.sin(2 * np.pi * freq * t) + data = np.vstack((data, data)) + kernel = create_kernel(freq, fs, 1, left_mode="uniform", right_mode="none") + filtered = apply_kernel(data, fs, freq, kernel) + for chan in filtered: + assert np.all(np.isclose(chan[period:], 0, 1e-10)) + + k = CombKernel(freq=freq, fs=fs, width=1, left_mode="uniform", right_mode="none") + duration_in_s = 2 + t = np.linspace(1 / fs, duration_in_s, num=fs * duration_in_s) + data = np.sin(2 * np.pi * freq * t) + data = np.vstack((data, data)) + filtered = k(data) + for chan in filtered: + assert np.all(np.isclose(chan[period:], 0, 1e-10)) + + s = StepwiseRemover(fs=fs, freq=freq) + duration_in_s = 2 + t = np.linspace(1 / fs, duration_in_s, num=fs * duration_in_s) + data = np.sin(2 * np.pi * freq * t) + data = np.vstack((data, data)) + filtered = s(data) + for chan in filtered: + assert np.all(np.isclose(chan[:], 0, 1e-10)) + + fs = 5000 + duration_in_s = 2 + for freq in range(10, 21, 1): + s = StepwiseRemover(fs=fs, freq=freq, period_steps=10) + t = np.linspace(1 / fs, duration_in_s, num=fs * duration_in_s) + nse = np.random.randn(t.shape[0]) + data = 1000 * np.sin(2 * np.pi * freq * t) + nse + filtered = s(data) + print("{:3.0f} ".format(freq), end="") + r2 = np.square(np.corrcoef(filtered, nse)[0, 1]) + print(np.max(np.abs(filtered)), r2) + assert np.all(r2 > 0.7071) + + print("Test successful")