misleep 0.2.7__tar.gz → 0.2.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {misleep-0.2.7 → misleep-0.2.8}/PKG-INFO +1 -1
- {misleep-0.2.7 → misleep-0.2.8}/misleep/config.ini +3 -3
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/dialog.py +1 -2
- {misleep-0.2.7 → misleep-0.2.8}/misleep/io/annotation_io.py +4 -1
- {misleep-0.2.7 → misleep-0.2.8}/misleep/io/base.py +2 -1
- {misleep-0.2.7 → misleep-0.2.8}/misleep/io/signal_io.py +4 -1
- misleep-0.2.8/misleep/utils/signals.py +120 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/viz/hypnogram.py +12 -1
- {misleep-0.2.7 → misleep-0.2.8}/misleep.egg-info/PKG-INFO +1 -1
- {misleep-0.2.7 → misleep-0.2.8}/setup.py +1 -1
- misleep-0.2.7/misleep/utils/signals.py +0 -73
- {misleep-0.2.7 → misleep-0.2.8}/LICENSE +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/README.md +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/__init__.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/__main__.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/analysis/__init__.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/analysis/auto_stage.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/analysis/auto_stage_model/P30_EEG_F_lightgbm.pkl +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/analysis/auto_stage_model/P30_EEG_P_lightgbm.pkl +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/analysis/auto_stage_model/ado_EEG_F_lightgbm.pkl +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/analysis/auto_stage_model/ado_EEG_P_lightgbm.pkl +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/analysis/auto_stage_model/adult_EEG_F_lightgbm.pkl +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/analysis/auto_stage_model/adult_EEG_P_lightgbm.pkl +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/analysis/detection.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/__init__.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/about.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/main_window.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/resources/__init__.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/resources/entire_logo.png +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/resources/logo.png +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/resources/misleep.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/resources/misleep.qrc +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/show.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/spec_window.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/thread.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/SWA_detect_dialog_ui.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/__init__.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/about_ui.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/auto_stage_dialog_ui.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/horizontal_line_dialog_ui.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/label_dialog_ui.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/main_window_ui.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/save_data_dialog_ui.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/spec_window_ui.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/spindle_detect_dialog_ui.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/state_spectral_dialog_ui.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/uis/transfer_result_dialog_ui.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/gui/utils.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/io/__init__.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/preprocessing/__init__.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/preprocessing/channel.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/preprocessing/signals.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/preprocessing/spectral.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/utils/__init__.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/utils/annotation.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/utils/logger_handler.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/utils/self_antropy.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/viz/__init__.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/viz/signals.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep/viz/spectral.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep.egg-info/SOURCES.txt +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep.egg-info/dependency_links.txt +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep.egg-info/requires.txt +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/misleep.egg-info/top_level.txt +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/setup.cfg +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/test/test_annotation_io.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/test/test_loadmat73.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/test/test_midata.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/test/test_show.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/test/test_signal_io.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/test/test_signals_viz.py +0 -0
- {misleep-0.2.7 → misleep-0.2.8}/test/test_spectral_viz.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[gui]
|
|
2
|
-
version = v0.2.
|
|
3
|
-
updatetime = 2025/
|
|
2
|
+
version = v0.2.8
|
|
3
|
+
updatetime = 2025/4/1
|
|
4
4
|
marker = ['good', 'first REM', 'WindEEG', 'W-R ', 'maker']
|
|
5
5
|
startend = ['burst-supression', 'REM', 'Wake', 'Spindle', 'SWA', 'start end label', 'start end label']
|
|
6
6
|
statemap = {"1": "NREM", "2": "REM", "3": "Wake", "4": "INIT", "5": "IS", "6": "MicroArousal"}
|
|
@@ -9,5 +9,5 @@ startendcolor = {"NREM": "orange", "REM": "skyblue", "Wake": "red"}
|
|
|
9
9
|
statecolorbgalpha = 0.1
|
|
10
10
|
markerlinecolor = "red"
|
|
11
11
|
startendlinecolor = "blue"
|
|
12
|
-
openpath =
|
|
12
|
+
openpath = D:
|
|
13
13
|
|
|
@@ -403,7 +403,7 @@ class stateSpectral_dialog(QDialog, Ui_StateSpectralDialog):
|
|
|
403
403
|
Wake_hour_spec = []
|
|
404
404
|
if self.HourSegmentCheckBox.isChecked():
|
|
405
405
|
for sec in range(0, end_sec-start_sec, 3600):
|
|
406
|
-
sleep_state = mianno.sleep_state[sec:sec+3600]
|
|
406
|
+
sleep_state = mianno.sleep_state[start_sec+sec: start_sec+sec+3600]
|
|
407
407
|
sleep_state = lst2group([[idx+sec, each] for idx, each in enumerate(sleep_state)])
|
|
408
408
|
|
|
409
409
|
# Merge 4 states' data
|
|
@@ -466,7 +466,6 @@ class stateSpectral_dialog(QDialog, Ui_StateSpectralDialog):
|
|
|
466
466
|
Init_figure.savefig(fd + '/Init_spectrum.pdf')
|
|
467
467
|
|
|
468
468
|
writer.close()
|
|
469
|
-
|
|
470
469
|
QMessageBox.about(self, "Info", "Spectral analysis finished")
|
|
471
470
|
|
|
472
471
|
def okEvent(self):
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
@Date: 2024/3/6
|
|
7
7
|
@Description: Annotation io, default is for MiSleep annotation, `NAME.txt`
|
|
8
8
|
"""
|
|
9
|
-
from misleep.io.base import MiAnnotation
|
|
10
9
|
from misleep.utils.annotation import marker2mianno, start_end2mianno, lst2group, sleep_state2mianno, transfer_time
|
|
11
10
|
import pandas as pd
|
|
12
11
|
|
|
@@ -43,6 +42,8 @@ def load_misleep_anno(file_path, state_map=None):
|
|
|
43
42
|
|
|
44
43
|
sleep_state = annotation[sleep_state_idx + 1:]
|
|
45
44
|
sleep_state = sleep_state2mianno(sleep_state)
|
|
45
|
+
|
|
46
|
+
from misleep.io.base import MiAnnotation
|
|
46
47
|
|
|
47
48
|
return MiAnnotation(sleep_state=sleep_state, start_end=start_end, marker=marker, state_map=state_map)
|
|
48
49
|
|
|
@@ -62,6 +63,8 @@ def load_bio_anno(file_path):
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
state_list = [state_map[each] for each in state_list]
|
|
66
|
+
|
|
67
|
+
from misleep.io.base import MiAnnotation
|
|
65
68
|
return MiAnnotation(sleep_state=state_list, marker=[], start_end=[])
|
|
66
69
|
|
|
67
70
|
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import math
|
|
10
10
|
|
|
11
11
|
import numpy as np
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
class MiData:
|
|
@@ -143,6 +143,7 @@ class MiData:
|
|
|
143
143
|
low : float
|
|
144
144
|
high : float
|
|
145
145
|
"""
|
|
146
|
+
from misleep.utils.signals import signal_filter
|
|
146
147
|
if chans is None or not isinstance(chans, list):
|
|
147
148
|
raise TypeError(f"'chans' should be a list of channel names, got {type(chans)}")
|
|
148
149
|
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
from hdf5storage import savemat
|
|
14
14
|
import pyedflib
|
|
15
15
|
import datetime
|
|
16
|
-
from misleep.io.base import MiData
|
|
17
16
|
from misleep.utils.logger_handler import logger
|
|
18
17
|
|
|
19
18
|
|
|
@@ -40,6 +39,8 @@ def load_mat(data_path):
|
|
|
40
39
|
|
|
41
40
|
from scipy.io import loadmat as scipy_loadmat
|
|
42
41
|
from mat73 import loadmat as mat73_loadmat
|
|
42
|
+
|
|
43
|
+
from misleep.io.base import MiData
|
|
43
44
|
|
|
44
45
|
try:
|
|
45
46
|
# Use scipy to load
|
|
@@ -183,6 +184,8 @@ def load_edf(data_path):
|
|
|
183
184
|
"""
|
|
184
185
|
|
|
185
186
|
signals, signal_headers, meta = pyedflib.highlevel.read_edf(edf_file=data_path)
|
|
187
|
+
|
|
188
|
+
from misleep.io.base import MiData
|
|
186
189
|
|
|
187
190
|
return MiData(signals=signals,
|
|
188
191
|
channels=[each['label'] for each in signal_headers],
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
@Project: misleep
|
|
4
|
+
@File: signals.py
|
|
5
|
+
@Author: Xueqiang Wang
|
|
6
|
+
@Date: 2024/2/29
|
|
7
|
+
@Description:
|
|
8
|
+
"""
|
|
9
|
+
import numpy as np
|
|
10
|
+
from scipy import signal
|
|
11
|
+
from copy import deepcopy
|
|
12
|
+
from misleep.io.base import MiData
|
|
13
|
+
from misleep.utils.annotation import lst2group
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def signal_filter(data, sf=256., btype='lowpass', low=0.5, high=30.):
|
|
17
|
+
"""
|
|
18
|
+
Filter the signal data, use butter filter in scipy
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
data : ndarray
|
|
23
|
+
1D array. Signal data need to be filtered.
|
|
24
|
+
sf : float
|
|
25
|
+
Sampling frequency of signal data. Default is 305.
|
|
26
|
+
btype : {'lowpass', 'highpass', 'bandpass'}, optional
|
|
27
|
+
The type of filter. Default is 'lowpass'.
|
|
28
|
+
low : float
|
|
29
|
+
Higher than this frequency can pass, used in 'highpass' and 'bandpass'
|
|
30
|
+
filter. Default is 0.5.
|
|
31
|
+
high : float
|
|
32
|
+
Lower than this frequency can pass, used in 'lowpass' and 'bandpass'
|
|
33
|
+
filter. Default is 30.
|
|
34
|
+
|
|
35
|
+
Returns
|
|
36
|
+
----------
|
|
37
|
+
filtered_data : 1D-array
|
|
38
|
+
Filtered data of signal data using butter filter
|
|
39
|
+
fname : str
|
|
40
|
+
|
|
41
|
+
"""
|
|
42
|
+
if not isinstance(sf, (int, float)):
|
|
43
|
+
raise TypeError(f"Sample frequency should be a float, got {type(sf)}")
|
|
44
|
+
|
|
45
|
+
if not isinstance(low, (int, float)):
|
|
46
|
+
raise TypeError(f"Low threshold should be a float, got {type(sf)}")
|
|
47
|
+
|
|
48
|
+
if not isinstance(high, (int, float)):
|
|
49
|
+
raise TypeError(f"high threshold should be a float, got {type(sf)}")
|
|
50
|
+
|
|
51
|
+
if btype == 'lowpass':
|
|
52
|
+
fnorm = high / (.5 * sf)
|
|
53
|
+
fname = f"{btype}_{high}"
|
|
54
|
+
elif btype == 'highpass':
|
|
55
|
+
fnorm = low / (.5 * sf)
|
|
56
|
+
fname = f"{btype}_{low}"
|
|
57
|
+
elif btype == 'bandpass':
|
|
58
|
+
fnorm = np.divide([low, high], .5 * sf)
|
|
59
|
+
fname = f"{btype}_{low}_{high}"
|
|
60
|
+
elif btype == 'bandstop':
|
|
61
|
+
fnorm = np.divide([low, high], .5 * sf)
|
|
62
|
+
fname = f"{btype}_{low}_{high}"
|
|
63
|
+
else:
|
|
64
|
+
raise ValueError("'%s' is an invalid type for filter, "
|
|
65
|
+
"you can only choose 'lowpass', 'highpass', 'bandpass' or 'bandstop'"
|
|
66
|
+
% btype)
|
|
67
|
+
|
|
68
|
+
# Use irrfilter of scipy.signal to construct a filter
|
|
69
|
+
b, a = signal.iirfilter(N=3, Wn=fnorm, btype=btype, analog=False,
|
|
70
|
+
output='ba', ftype='butter', fs=None)
|
|
71
|
+
|
|
72
|
+
filtered_data = signal.filtfilt(b=b, a=a, x=data)
|
|
73
|
+
|
|
74
|
+
return filtered_data, fname
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def crop_state_data(midata, mianno):
|
|
78
|
+
"""Crop the data with annotation into different state data, typically seperate the data into NREM data, REM data, Wake and Init data
|
|
79
|
+
Apply this to every channels
|
|
80
|
+
"""
|
|
81
|
+
# Get the sleep state data
|
|
82
|
+
sleep_state = deepcopy(mianno.sleep_state)
|
|
83
|
+
sleep_state = lst2group([[idx, each] for idx, each in enumerate(sleep_state)])
|
|
84
|
+
signals = deepcopy(midata.signals)
|
|
85
|
+
NREM_signals = []
|
|
86
|
+
REM_signals = []
|
|
87
|
+
Wake_signals = []
|
|
88
|
+
Init_signals = []
|
|
89
|
+
|
|
90
|
+
for idx, signal in enumerate(signals):
|
|
91
|
+
sf = midata.sf[idx]
|
|
92
|
+
|
|
93
|
+
NREM_data = [signal[int(each[0]*sf): int(each[1]*sf)]
|
|
94
|
+
for each in sleep_state if each[2] == 1]
|
|
95
|
+
NREM_data = np.array([element for sublist in NREM_data for element in sublist])
|
|
96
|
+
NREM_signals.append(NREM_data)
|
|
97
|
+
|
|
98
|
+
REM_data = [signal[int(each[0]*sf): int(each[1]*sf)]
|
|
99
|
+
for each in sleep_state if each[2] == 2]
|
|
100
|
+
REM_data = np.array([element for sublist in REM_data for element in sublist])
|
|
101
|
+
REM_signals.append(REM_data)
|
|
102
|
+
|
|
103
|
+
Wake_data = [signal[int(each[0]*sf): int(each[1]*sf)]
|
|
104
|
+
for each in sleep_state if each[2] == 3]
|
|
105
|
+
Wake_data = np.array([element for sublist in Wake_data for element in sublist])
|
|
106
|
+
Wake_signals.append(Wake_data)
|
|
107
|
+
|
|
108
|
+
Init_data = [signal[int(each[0]*sf): int(each[1]*sf)]
|
|
109
|
+
for each in sleep_state if each[2] == 4]
|
|
110
|
+
Init_data = np.array([element for sublist in Init_data for element in sublist])
|
|
111
|
+
Init_signals.append(Init_data)
|
|
112
|
+
|
|
113
|
+
NREM_data = MiData(signals=NREM_signals, channels=midata.channels, sf=midata.sf, time=midata.time, describe='NREM cropped data')
|
|
114
|
+
REM_data = MiData(signals=REM_signals, channels=midata.channels, sf=midata.sf, time=midata.time, describe='REM cropped data')
|
|
115
|
+
Wake_data = MiData(signals=Wake_signals, channels=midata.channels, sf=midata.sf, time=midata.time, describe='Wake cropped data')
|
|
116
|
+
Init_data = MiData(signals=Init_signals, channels=midata.channels, sf=midata.sf, time=midata.time, describe='Init cropped data')
|
|
117
|
+
|
|
118
|
+
return NREM_data, REM_data, Wake_data, Init_data
|
|
119
|
+
|
|
120
|
+
|
|
@@ -11,7 +11,7 @@ import matplotlib.pyplot as plt
|
|
|
11
11
|
import matplotlib
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
def plot_hypno(sleep_state, state_map=None):
|
|
14
|
+
def plot_hypno(sleep_state, state_map=None, time_range=[0, -1]):
|
|
15
15
|
"""
|
|
16
16
|
Draw hypnogram with sleep_state list
|
|
17
17
|
|
|
@@ -21,10 +21,21 @@ def plot_hypno(sleep_state, state_map=None):
|
|
|
21
21
|
List of sleep state, should be integers, and use state_map map to contents
|
|
22
22
|
state_map : dict
|
|
23
23
|
Dict of mapping from sleep state content to it's meaning
|
|
24
|
+
time_range : list
|
|
25
|
+
Time range to plot the hypnogram
|
|
24
26
|
"""
|
|
25
27
|
|
|
26
28
|
if not isinstance(sleep_state, list):
|
|
27
29
|
raise TypeError(f"'sleep_state' should be a list, got {type(sleep_state)}")
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
if time_range != [0, -1]:
|
|
33
|
+
sleep_state_ = sleep_state[time_range[0]:time_range[1]]
|
|
34
|
+
except Exception as e:
|
|
35
|
+
print("Invalid time range, plot as default")
|
|
36
|
+
sleep_state_ = sleep_state
|
|
37
|
+
|
|
38
|
+
sleep_state = sleep_state_
|
|
28
39
|
|
|
29
40
|
if state_map is None:
|
|
30
41
|
state_map = {
|
|
@@ -11,7 +11,7 @@ MAINTAINER_EMAIL = "swang@gmail.com"
|
|
|
11
11
|
URL = "https://github.com/BryanWang0702/MiSleep/"
|
|
12
12
|
LICENSE = "BSD (3-clause)"
|
|
13
13
|
DOWNLOAD_URL = "https://github.com/BryanWang0702/MiSleep/"
|
|
14
|
-
VERSION = "0.2.
|
|
14
|
+
VERSION = "0.2.8"
|
|
15
15
|
|
|
16
16
|
INSTALL_REQUIRES = [
|
|
17
17
|
"numpy>=1.18.1",
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# -*- coding: UTF-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
@Project: misleep
|
|
4
|
-
@File: signals.py
|
|
5
|
-
@Author: Xueqiang Wang
|
|
6
|
-
@Date: 2024/2/29
|
|
7
|
-
@Description:
|
|
8
|
-
"""
|
|
9
|
-
import numpy as np
|
|
10
|
-
from scipy import signal
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def signal_filter(data, sf=256., btype='lowpass', low=0.5, high=30.):
|
|
14
|
-
"""
|
|
15
|
-
Filter the signal data, use butter filter in scipy
|
|
16
|
-
|
|
17
|
-
Parameters
|
|
18
|
-
----------
|
|
19
|
-
data : ndarray
|
|
20
|
-
1D array. Signal data need to be filtered.
|
|
21
|
-
sf : float
|
|
22
|
-
Sampling frequency of signal data. Default is 305.
|
|
23
|
-
btype : {'lowpass', 'highpass', 'bandpass'}, optional
|
|
24
|
-
The type of filter. Default is 'lowpass'.
|
|
25
|
-
low : float
|
|
26
|
-
Higher than this frequency can pass, used in 'highpass' and 'bandpass'
|
|
27
|
-
filter. Default is 0.5.
|
|
28
|
-
high : float
|
|
29
|
-
Lower than this frequency can pass, used in 'lowpass' and 'bandpass'
|
|
30
|
-
filter. Default is 30.
|
|
31
|
-
|
|
32
|
-
Returns
|
|
33
|
-
----------
|
|
34
|
-
filtered_data : 1D-array
|
|
35
|
-
Filtered data of signal data using butter filter
|
|
36
|
-
fname : str
|
|
37
|
-
|
|
38
|
-
"""
|
|
39
|
-
if not isinstance(sf, (int, float)):
|
|
40
|
-
raise TypeError(f"Sample frequency should be a float, got {type(sf)}")
|
|
41
|
-
|
|
42
|
-
if not isinstance(low, (int, float)):
|
|
43
|
-
raise TypeError(f"Low threshold should be a float, got {type(sf)}")
|
|
44
|
-
|
|
45
|
-
if not isinstance(high, (int, float)):
|
|
46
|
-
raise TypeError(f"high threshold should be a float, got {type(sf)}")
|
|
47
|
-
|
|
48
|
-
if btype == 'lowpass':
|
|
49
|
-
fnorm = high / (.5 * sf)
|
|
50
|
-
fname = f"{btype}_{high}"
|
|
51
|
-
elif btype == 'highpass':
|
|
52
|
-
fnorm = low / (.5 * sf)
|
|
53
|
-
fname = f"{btype}_{low}"
|
|
54
|
-
elif btype == 'bandpass':
|
|
55
|
-
fnorm = np.divide([low, high], .5 * sf)
|
|
56
|
-
fname = f"{btype}_{low}_{high}"
|
|
57
|
-
elif btype == 'bandstop':
|
|
58
|
-
fnorm = np.divide([low, high], .5 * sf)
|
|
59
|
-
fname = f"{btype}_{low}_{high}"
|
|
60
|
-
else:
|
|
61
|
-
raise ValueError("'%s' is an invalid type for filter, "
|
|
62
|
-
"you can only choose 'lowpass', 'highpass', 'bandpass' or 'bandstop'"
|
|
63
|
-
% btype)
|
|
64
|
-
|
|
65
|
-
# Use irrfilter of scipy.signal to construct a filter
|
|
66
|
-
b, a = signal.iirfilter(N=3, Wn=fnorm, btype=btype, analog=False,
|
|
67
|
-
output='ba', ftype='butter', fs=None)
|
|
68
|
-
|
|
69
|
-
filtered_data = signal.filtfilt(b=b, a=a, x=data)
|
|
70
|
-
|
|
71
|
-
return filtered_data, fname
|
|
72
|
-
|
|
73
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|