├── .DS_Store ├── README.md ├── documentations ├── GSRAutoFeatureExtraction │ └── GSRAutoFeatureExtraction.ipynb └── GSRStatFeatureExtraction │ └── GSRStatFeatureExtraction.ipynb ├── main.py └── pyEDA ├── __ init __.py ├── __pycache__ ├── DNN_Features.cpython-38.pyc ├── autoencoder.cpython-38.pyc ├── calculateFeatures.cpython-38.pyc ├── calculate_onSetOffSet.cpython-38.pyc ├── calculate_thepeaks.cpython-38.pyc ├── cvxEDA.cpython-38.pyc ├── filtering.cpython-38.pyc ├── openShimmerFile.cpython-38.pyc ├── preprocessing.cpython-38.pyc ├── pyEDA.cpython-37.pyc ├── pyEDA.cpython-38.pyc └── windowing.cpython-38.pyc ├── autoencoder.py ├── calculateFeatures.py ├── calculate_onSetOffSet.py ├── calculate_thepeaks.py ├── checkpoint.t7 ├── cvxEDA.py ├── filtering.py ├── openShimmerFile.py ├── preprocessing.py ├── pyEDA.py └── windowing.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyEDA 2 | This is pyEDA v.2.0. 3 |
This package includes all you need for Electrodermal Activity analysis also known as GSR. It contains preprocessing of the EDA signal and its feature extraction. Features are extracted using statistical and automatic methods. 4 |
Convolutional autoencoder is used to extract the automatic featues. 5 | 6 | # Data Collection 7 | All the plots and the data collected for this package are collected from Shimmer GSR+ wearable sensor with 128 Hz frequency sampling rate. 8 | 9 | # How to use? 10 | After cloning the repository to your local directory use the following command to import the library in your code: 11 | ``` 12 | from pyEDA.main import * 13 | ``` 14 | # Extract Statistical Features 15 | Use the following command in your code to analysis the data: 16 | ``` 17 | m, wd, eda_clean = process_statistical(eda, use_scipy=True, sample_rate=128, new_sample_rate=40, segment_width=600, segment_overlap=0) 18 | ``` 19 | inputs:: 20 |
21 | eda: the GSR signal 22 |
23 | use_scipy: set true to use scipy for peak extraction from phasic gsr (recommended) 24 |
25 | sample_rate: sample rate which the data is collected at 26 |
27 | new_sample_rate: new sample rate to downsample the data to 28 |
29 | segment_width: segmentation of signal in seconds 30 |
31 | segment_overlap: overlap of segments in seconds 32 |
33 |
34 | returns:: 35 |
36 | m: all the measurements of the signals for each of the segment indices (number of peaks, mean of EDA, maximum value of the peaks) 37 |
38 | wd: filtered phasic gsr, phasic gsr, tonic gsr, and peacklist for each of the segment indices 39 |
40 | eda_clean: preprocessed gsr data 41 | 42 | # Extract Automatic Features 43 | Use the following command in your code to train the autoencoder: 44 | ``` 45 | prepare_automatic(eda_signals, sample_rate=128, new_sample_rate=40, k=32, epochs=100, batch_size=10) 46 | ``` 47 | inputs:: 48 |
49 | eda_signals: All eda signals (must be normalized to 0-1 range since the activation function of last layer is sigmoid.) targeted for feature extraction (2d list: nxm, n=number of signals, m=length of each signal) 50 |
51 | sample_rate: sample rate which the data is collected at 52 |
53 | new_sample_rate: new sample rate to downsample the data to 54 |
55 | epochs: the number of epochs to train the autoencoder 56 |
57 | k: the number of automatic features to extract 58 |
59 | batch_size: the batch size to train the autoencoder 60 |
61 | 62 | After the autoencoder is trained and saved, use the following command in your code to extract the automatic features: 63 | ``` 64 | automatic_features = process_automatic(eda) 65 | ``` 66 | inputs:: 67 |
68 | eda: the GSR signal 69 |
70 | returns:: 71 |
72 | automatic_features: extracted automatic features 73 |
74 | 75 | # Documentation 76 | Here you can find the link to different notebooks about all the aspects of analysis of the GSR signal. These documentations include information about preprocessing and feature extraction of EDA signal. 77 |
78 |
79 | These show how to handle various analysis tasks with pyEDA, from a random generated GSR data. 80 |
81 |
82 | Here you can find the list of notebooks for feature extraction of EDA signal: 83 | * [Statistical Feature Extraction](documentations/GSRStatFeatureExtraction/GSRStatFeatureExtraction.ipynb), a notebook explaining statistical feature extraction of GSR signal. 84 | 85 | * [Automatic Feature Extraction](documentations/GSRAutoFeatureExtraction/GSRAutoFeatureExtraction.ipynb), a notebook explaining automatic feature extraction of GSR using an autoencoder. 86 | 87 | # Citation 88 | ``` 89 | pyEDA: An Open-Source Python Toolkit for Pre-processing and Feature Extraction of Electrodermal Activity 90 | ``` 91 | ``` 92 | Full bibtex reference: 93 | 94 | @article{aqajari2021pyeda, 95 | title={pyEDA: An Open-Source Python Toolkit for Pre-processing and Feature Extraction of Electrodermal Activity}, 96 | author={Aqajari, Seyed Amir Hossein and Naeini, Emad Kasaeyan and Mehrabadi, Milad Asgari and Labbaf, Sina and Dutt, Nikil and Rahmani, Amir M}, 97 | journal={Procedia Computer Science}, 98 | volume={184}, 99 | pages={99--106}, 100 | year={2021}, 101 | publisher={Elsevier} 102 | } 103 | ``` 104 | -------------------------------------------------------------------------------- /documentations/GSRAutoFeatureExtraction/GSRAutoFeatureExtraction.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "tUgLluwxHIGe" 8 | }, 9 | "source": [ 10 | "# Visualise the random GSR raw data\n", 11 | "First we visualize the list including all random GSR raw data stored in \"eda_signals\" list.\n", 12 | "20 different EDA signals with sample rate of 250 with duration of 10 seconds. (size of list: 20 item with length of 2500 each)" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": 12, 18 | "metadata": { 19 | "colab": {}, 20 | "colab_type": "code", 21 | "id": "DLaWVrxcHGqe" 22 | }, 23 | "outputs": [ 24 | { 25 | "name": "stdout", 26 | "output_type": "stream", 27 | "text": [ 28 | "[array([0.99788875, 0.99791173, 0.99790225, ..., 2.41614557, 2.41018055,\n", 29 | " 2.40427158]), array([1.01349388, 1.01347954, 1.01336015, ..., 2.10845936, 2.10457421,\n", 30 | " 2.10068955]), array([1.00160421, 1.00165555, 1.00172889, ..., 2.30466752, 2.29999211,\n", 31 | " 2.29519113]), array([0.99551765, 0.99556447, 0.99562397, ..., 2.3673548 , 2.36096327,\n", 32 | " 2.35462749]), array([1.00300461, 1.00309038, 1.00326275, ..., 2.21641778, 2.2116888 ,\n", 33 | " 2.20699479]), array([0.99884373, 0.99885445, 0.99880998, ..., 1.62938513, 1.62777988,\n", 34 | " 1.62620904]), array([1.00157543, 1.00156187, 1.00144749, ..., 2.07630445, 2.07251311,\n", 35 | " 2.06874286]), array([0.98898952, 0.98907283, 0.9892391 , ..., 2.2651361 , 2.26030227,\n", 36 | " 2.25551334]), array([1.00162299, 1.00165728, 1.00168017, ..., 1.57030997, 1.56902293,\n", 37 | " 1.56769941]), array([0.9952017 , 0.99526053, 0.99535532, ..., 2.48149712, 2.47449872,\n", 38 | " 2.46752639]), array([0.99722989, 0.99727296, 0.99732201, ..., 2.22301822, 2.21848526,\n", 39 | " 2.21399048]), array([1.00237643, 1.00247609, 1.00268887, ..., 2.14438108, 2.14050661,\n", 40 | " 2.13665439]), array([1.00944636, 1.00944058, 1.00934806, ..., 2.45667342, 2.44975797,\n", 41 | " 2.44292707]), array([1.00161254, 1.00163071, 1.00160743, ..., 2.53148704, 2.52537882,\n", 42 | " 2.51912564]), array([0.99404056, 0.99408347, 0.99413213, ..., 2.36397102, 2.35798417,\n", 43 | " 2.35203966]), array([1.00597901, 1.00603288, 1.00611264, ..., 2.42793328, 2.42141598,\n", 44 | " 2.41485286]), array([1.00207033, 1.00208473, 1.00205017, ..., 2.62920697, 2.6264717 ,\n", 45 | " 2.62323349]), array([1.01019068, 1.01020111, 1.01015501, ..., 2.3772727 , 2.3712914 ,\n", 46 | " 2.36536885]), array([1.00333 , 1.00336099, 1.00337514, ..., 2.02576555, 2.02226725,\n", 47 | " 2.01880769]), array([0.9965604 , 0.99663277, 0.99676709, ..., 2.18499902, 2.18052202,\n", 48 | " 2.17615544])]\n", 49 | "(20, 2500)\n" 50 | ] 51 | }, 52 | { 53 | "data": { 54 | "text/plain": [ 55 | "[]" 56 | ] 57 | }, 58 | "execution_count": 12, 59 | "metadata": {}, 60 | "output_type": "execute_result" 61 | }, 62 | { 63 | "data": { 64 | "image/png": "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\n", 65 | "text/plain": [ 66 | "
" 67 | ] 68 | }, 69 | "metadata": { 70 | "needs_background": "light" 71 | }, 72 | "output_type": "display_data" 73 | } 74 | ], 75 | "source": [ 76 | "import numpy as np\n", 77 | "import matplotlib.pyplot as plt\n", 78 | "\n", 79 | "# Visualise the list of signals\n", 80 | "print(eda_signals)\n", 81 | "print(np.array(eda_signals).shape)\n", 82 | "\n", 83 | "# Visualise one of the signals in the list\n", 84 | "plt.figure(figsize=(12,4))\n", 85 | "plt.plot(eda_signals[0])" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "# Import the pyEDA library\n", 93 | "In order to use pyEDA for statistical feature extraction, we need to import it in our code after cloning the repository in the same directory as our code." 94 | ] 95 | }, 96 | { 97 | "cell_type": "code", 98 | "execution_count": 6, 99 | "metadata": {}, 100 | "outputs": [], 101 | "source": [ 102 | "from pyEDA.main import *" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": { 108 | "colab_type": "text", 109 | "id": "BPj6sI0AIhU4" 110 | }, 111 | "source": [ 112 | "# Train the autoencoder\n", 113 | "In order to extract automatic features from our gsr signal, we need to train our autoencoder using our gs signals using the prepare_automatic function.\n", 114 | "\n", 115 | "NOTE: If you need to process faster, you can downsample the signal. But remember if you downsample the signal, the size of GSR signals which autoencoder is being trained with is going to also change." 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": 9, 121 | "metadata": { 122 | "colab": { 123 | "base_uri": "https://localhost:8080/", 124 | "height": 283 125 | }, 126 | "colab_type": "code", 127 | "id": "ET0ptLJAFyzF", 128 | "outputId": "d1fd1c46-dff7-4a4d-a879-0ce6fac3a250" 129 | }, 130 | "outputs": [ 131 | { 132 | "name": "stdout", 133 | "output_type": "stream", 134 | "text": [ 135 | "If you are using this tool for your research please cite this paper: \"GSR Analysis for Stress: Development and Validation of an Open Source Tool for Noisy Naturalistic GSR Data\"\n", 136 | "epoch : 1/100, loss = 2.802090\n", 137 | "epoch : 2/100, loss = 0.460173\n", 138 | "epoch : 3/100, loss = 1.250345\n", 139 | "epoch : 4/100, loss = 0.448691\n", 140 | "epoch : 5/100, loss = 0.634804\n", 141 | "epoch : 6/100, loss = 0.268244\n", 142 | "epoch : 7/100, loss = 0.176262\n", 143 | "epoch : 8/100, loss = 0.169627\n", 144 | "epoch : 9/100, loss = 0.140845\n", 145 | "epoch : 10/100, loss = 0.141272\n", 146 | "epoch : 11/100, loss = 0.151228\n", 147 | "epoch : 12/100, loss = 0.138227\n", 148 | "epoch : 13/100, loss = 0.115393\n", 149 | "epoch : 14/100, loss = 0.115849\n", 150 | "epoch : 15/100, loss = 0.124378\n", 151 | "epoch : 16/100, loss = 0.114096\n", 152 | "epoch : 17/100, loss = 0.105679\n", 153 | "epoch : 18/100, loss = 0.109966\n", 154 | "epoch : 19/100, loss = 0.109611\n", 155 | "epoch : 20/100, loss = 0.103991\n", 156 | "epoch : 21/100, loss = 0.104039\n", 157 | "epoch : 22/100, loss = 0.105153\n", 158 | "epoch : 23/100, loss = 0.103055\n", 159 | "epoch : 24/100, loss = 0.102282\n", 160 | "epoch : 25/100, loss = 0.102315\n", 161 | "epoch : 26/100, loss = 0.101455\n", 162 | "epoch : 27/100, loss = 0.101220\n", 163 | "epoch : 28/100, loss = 0.101299\n", 164 | "epoch : 29/100, loss = 0.101008\n", 165 | "epoch : 30/100, loss = 0.100827\n", 166 | "epoch : 31/100, loss = 0.100611\n", 167 | "epoch : 32/100, loss = 0.100405\n", 168 | "epoch : 33/100, loss = 0.100391\n", 169 | "epoch : 34/100, loss = 0.100382\n", 170 | "epoch : 35/100, loss = 0.100376\n", 171 | "epoch : 36/100, loss = 0.100307\n", 172 | "epoch : 37/100, loss = 0.100202\n", 173 | "epoch : 38/100, loss = 0.100183\n", 174 | "epoch : 39/100, loss = 0.100175\n", 175 | "epoch : 40/100, loss = 0.100188\n", 176 | "epoch : 41/100, loss = 0.100199\n", 177 | "epoch : 42/100, loss = 0.100165\n", 178 | "epoch : 43/100, loss = 0.100151\n", 179 | "epoch : 44/100, loss = 0.100152\n", 180 | "epoch : 45/100, loss = 0.100158\n", 181 | "epoch : 46/100, loss = 0.100170\n", 182 | "epoch : 47/100, loss = 0.100172\n", 183 | "epoch : 48/100, loss = 0.100172\n", 184 | "epoch : 49/100, loss = 0.100175\n", 185 | "epoch : 50/100, loss = 0.100181\n", 186 | "epoch : 51/100, loss = 0.100189\n", 187 | "epoch : 52/100, loss = 0.100197\n", 188 | "epoch : 53/100, loss = 0.100205\n", 189 | "epoch : 54/100, loss = 0.100212\n", 190 | "epoch : 55/100, loss = 0.100216\n", 191 | "epoch : 56/100, loss = 0.100223\n", 192 | "epoch : 57/100, loss = 0.100232\n", 193 | "epoch : 58/100, loss = 0.100242\n", 194 | "epoch : 59/100, loss = 0.100250\n", 195 | "epoch : 60/100, loss = 0.100255\n", 196 | "epoch : 61/100, loss = 0.100261\n", 197 | "epoch : 62/100, loss = 0.100270\n", 198 | "epoch : 63/100, loss = 0.100280\n", 199 | "epoch : 64/100, loss = 0.100288\n", 200 | "epoch : 65/100, loss = 0.100293\n", 201 | "epoch : 66/100, loss = 0.100299\n", 202 | "epoch : 67/100, loss = 0.100307\n", 203 | "epoch : 68/100, loss = 0.100316\n", 204 | "epoch : 69/100, loss = 0.100324\n", 205 | "epoch : 70/100, loss = 0.100330\n", 206 | "epoch : 71/100, loss = 0.100336\n", 207 | "epoch : 72/100, loss = 0.100344\n", 208 | "epoch : 73/100, loss = 0.100351\n", 209 | "epoch : 74/100, loss = 0.100358\n", 210 | "epoch : 75/100, loss = 0.100365\n", 211 | "epoch : 76/100, loss = 0.100372\n", 212 | "epoch : 77/100, loss = 0.100378\n", 213 | "epoch : 78/100, loss = 0.100385\n", 214 | "epoch : 79/100, loss = 0.100392\n", 215 | "epoch : 80/100, loss = 0.100399\n", 216 | "epoch : 81/100, loss = 0.100405\n", 217 | "epoch : 82/100, loss = 0.100411\n", 218 | "epoch : 83/100, loss = 0.100417\n", 219 | "epoch : 84/100, loss = 0.100424\n", 220 | "epoch : 85/100, loss = 0.100430\n", 221 | "epoch : 86/100, loss = 0.100436\n", 222 | "epoch : 87/100, loss = 0.100442\n", 223 | "epoch : 88/100, loss = 0.100448\n", 224 | "epoch : 89/100, loss = 0.100454\n", 225 | "epoch : 90/100, loss = 0.100460\n", 226 | "epoch : 91/100, loss = 0.100465\n", 227 | "epoch : 92/100, loss = 0.100471\n", 228 | "epoch : 93/100, loss = 0.100477\n", 229 | "epoch : 94/100, loss = 0.100482\n", 230 | "epoch : 95/100, loss = 0.100488\n", 231 | "epoch : 96/100, loss = 0.100493\n", 232 | "epoch : 97/100, loss = 0.100499\n", 233 | "epoch : 98/100, loss = 0.100504\n", 234 | "epoch : 99/100, loss = 0.100509\n", 235 | "epoch : 100/100, loss = 0.100514\n" 236 | ] 237 | } 238 | ], 239 | "source": [ 240 | "prepare_automatic(eda_signals, sample_rate=250, new_sample_rate=250, k=32, epochs=100, batch_size=10)" 241 | ] 242 | }, 243 | { 244 | "cell_type": "markdown", 245 | "metadata": { 246 | "colab_type": "text", 247 | "id": "IYaBHsI9J_-X" 248 | }, 249 | "source": [ 250 | "# Feature Extraction\n", 251 | "After our autoencoder is trained, we use the following function in order to extract automatic features from any GSR signal using process_automatic function. \n", 252 | "\n", 253 | "NOTE: the size of gsr signals here should be equal to the size of GSR signals which the autoencoder were being trained by. (The same window size for entire study)\n", 254 | "If another window size is needed to be used, autoencoder needs to be retrained using new list of GSR signals with that size.\n", 255 | "\n", 256 | "Example: Here each of our GSR signals in our eda_signals list has the length of 2500. Therefore, if we dont downsample the signal we need to call process_automatic function with eda signals with the length of 2500. \n", 257 | "However, if we downsample the signal to 40 for example. We need to call process_automatic function with GSR signals with the length of 2500*40/250 = 400." 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": 10, 263 | "metadata": { 264 | "colab": { 265 | "base_uri": "https://localhost:8080/", 266 | "height": 283 267 | }, 268 | "colab_type": "code", 269 | "id": "RdxdoDrKFrG9", 270 | "outputId": "3d841b04-cfd3-401a-82e5-d825a8622d03" 271 | }, 272 | "outputs": [], 273 | "source": [ 274 | "automatic_features = process_automatic(eda_signals[0])" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": 11, 280 | "metadata": {}, 281 | "outputs": [ 282 | { 283 | "name": "stdout", 284 | "output_type": "stream", 285 | "text": [ 286 | "[ 2.1938908 -3.3337872 -0.59538203 -1.1390333 1.4525739 1.302319\n", 287 | " -2.3032336 -0.2162954 1.402661 -0.9634922 -3.0058932 -1.1702341\n", 288 | " -1.2339394 1.248246 0.04604254 -0.36458677 -1.0588155 2.55221\n", 289 | " -0.06742256 2.637837 0.07761233 0.0241823 -0.52685773 0.29004225\n", 290 | " 3.5780683 -1.5817611 1.2679836 0.7586949 3.0091262 0.6436667\n", 291 | " 2.379496 -2.8622315 ]\n" 292 | ] 293 | } 294 | ], 295 | "source": [ 296 | "print(automatic_features)" 297 | ] 298 | } 299 | ], 300 | "metadata": { 301 | "colab": { 302 | "name": "GSR_Preprocessing.ipynb", 303 | "provenance": [] 304 | }, 305 | "kernelspec": { 306 | "display_name": "Python 3", 307 | "language": "python", 308 | "name": "python3" 309 | }, 310 | "language_info": { 311 | "codemirror_mode": { 312 | "name": "ipython", 313 | "version": 3 314 | }, 315 | "file_extension": ".py", 316 | "mimetype": "text/x-python", 317 | "name": "python", 318 | "nbconvert_exporter": "python", 319 | "pygments_lexer": "ipython3", 320 | "version": "3.8.5" 321 | } 322 | }, 323 | "nbformat": 4, 324 | "nbformat_minor": 1 325 | } 326 | -------------------------------------------------------------------------------- /documentations/GSRStatFeatureExtraction/GSRStatFeatureExtraction.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "BKgqTIwZT_cz" 8 | }, 9 | "source": [ 10 | "# Visualise the random GSR raw data\n", 11 | "First we visualize our random GSR raw data stored in \"eda\" numpy array with sample rate of 250 Hz" 12 | ] 13 | }, 14 | { 15 | "cell_type": "code", 16 | "execution_count": 36, 17 | "metadata": { 18 | "colab": { 19 | "base_uri": "https://localhost:8080/", 20 | "height": 301 21 | }, 22 | "colab_type": "code", 23 | "id": "w-uUe_1sH4dn", 24 | "outputId": "971f79ac-3166-44a4-f9d6-0f8e580cc951" 25 | }, 26 | "outputs": [ 27 | { 28 | "data": { 29 | "text/plain": [ 30 | "
" 31 | ] 32 | }, 33 | "execution_count": 36, 34 | "metadata": {}, 35 | "output_type": "execute_result" 36 | }, 37 | { 38 | "data": { 39 | "image/png": "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\n", 40 | "text/plain": [ 41 | "
" 42 | ] 43 | }, 44 | "metadata": { 45 | "needs_background": "light" 46 | }, 47 | "output_type": "display_data" 48 | }, 49 | { 50 | "data": { 51 | "text/plain": [ 52 | "
" 53 | ] 54 | }, 55 | "metadata": {}, 56 | "output_type": "display_data" 57 | } 58 | ], 59 | "source": [ 60 | "import numpy as np\n", 61 | "import matplotlib.pyplot as plt\n", 62 | "\n", 63 | "# Visualise the data\n", 64 | "plt.figure(figsize=(12,4))\n", 65 | "plt.plot(eda)\n", 66 | "plt.figure(figsize=(12,4))" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "metadata": {}, 72 | "source": [ 73 | "# Import the pyEDA library\n", 74 | "In order to use pyEDA for statistical feature extraction, we need to import it in our code after cloning the repository in the same directory as our code." 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 37, 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "from pyEDA.main import *" 84 | ] 85 | }, 86 | { 87 | "cell_type": "markdown", 88 | "metadata": { 89 | "colab_type": "text", 90 | "id": "nMBQ3A44N4io" 91 | }, 92 | "source": [ 93 | "# Process the EDA\n", 94 | "For processing the EDA and calculating the mean, the max, and the number of peaks, we use process_statistical function. \n", 95 | "\n", 96 | "Data here is downsampled to 40Hz frequency. Preprocessings are also handeled inside of process_statistical function and there is no need to worry about them. (Unless you want to remove some of the proprocessing parts explained in the paper.)\n", 97 | "\n", 98 | "Our random generated EDA signal is so clean therefore we commented out the call to butter_lowpassfilter function inside statistical_feature_extraction function. (You may need to comment out that part in case your signal is so clean and without any noise.)" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": 38, 104 | "metadata": { 105 | "colab": {}, 106 | "colab_type": "code", 107 | "id": "FpywjRIDNaLK" 108 | }, 109 | "outputs": [ 110 | { 111 | "name": "stdout", 112 | "output_type": "stream", 113 | "text": [ 114 | "If you are using this tool for your research please cite this paper: \"GSR Analysis for Stress: Development and Validation of an Open Source Tool for Noisy Naturalistic GSR Data\"\n", 115 | " pcost dcost gap pres dres\n", 116 | " 0: -8.2438e+02 -8.2396e+02 5e+02 2e+01 1e+01\n", 117 | " 1: -8.2503e+02 -8.5068e+02 3e+01 1e+00 9e-01\n", 118 | " 2: -8.2983e+02 -8.4319e+02 1e+01 5e-01 3e-01\n", 119 | " 3: -8.3186e+02 -8.4454e+02 1e+01 4e-01 3e-01\n", 120 | " 4: -8.3476e+02 -8.4113e+02 6e+00 2e-01 1e-01\n", 121 | " 5: -8.3726e+02 -8.4262e+02 5e+00 1e-01 6e-02\n", 122 | " 6: -8.3822e+02 -8.4094e+02 3e+00 4e-02 3e-02\n", 123 | " 7: -8.3845e+02 -8.4103e+02 3e+00 3e-02 2e-02\n", 124 | " 8: -8.3899e+02 -8.4011e+02 1e+00 1e-02 8e-03\n", 125 | " 9: -8.3917e+02 -8.3988e+02 7e-01 4e-03 3e-03\n", 126 | "10: -8.3934e+02 -8.3953e+02 2e-01 2e-04 1e-04\n", 127 | "11: -8.3943e+02 -8.3947e+02 4e-02 2e-05 1e-05\n", 128 | "12: -8.3945e+02 -8.3946e+02 1e-02 3e-06 2e-06\n", 129 | "13: -8.3945e+02 -8.3945e+02 3e-03 5e-07 3e-07\n", 130 | "14: -8.3945e+02 -8.3945e+02 4e-04 3e-08 2e-08\n", 131 | "15: -8.3945e+02 -8.3945e+02 7e-05 3e-09 2e-09\n", 132 | "16: -8.3945e+02 -8.3945e+02 1e-05 4e-10 3e-10\n", 133 | "17: -8.3945e+02 -8.3945e+02 2e-06 8e-11 4e-11\n", 134 | "18: -8.3945e+02 -8.3945e+02 2e-07 6e-11 6e-12\n", 135 | "Optimal solution found.\n", 136 | " pcost dcost gap pres dres\n", 137 | " 0: -1.0812e+03 -1.0807e+03 4e+02 2e+01 1e+01\n", 138 | " 1: -1.0810e+03 -1.0986e+03 2e+01 9e-01 5e-01\n", 139 | " 2: -1.0838e+03 -1.0930e+03 9e+00 4e-01 2e-01\n", 140 | " 3: -1.0848e+03 -1.0940e+03 9e+00 4e-01 2e-01\n", 141 | " 4: -1.0883e+03 -1.0936e+03 5e+00 2e-01 9e-02\n", 142 | " 5: -1.0904e+03 -1.0954e+03 5e+00 1e-01 6e-02\n", 143 | " 6: -1.0923e+03 -1.0950e+03 3e+00 5e-02 3e-02\n", 144 | " 7: -1.0930e+03 -1.0953e+03 2e+00 3e-02 2e-02\n", 145 | " 8: -1.0935e+03 -1.0947e+03 1e+00 1e-02 7e-03\n", 146 | " 9: -1.0936e+03 -1.0947e+03 1e+00 1e-02 6e-03\n", 147 | "10: -1.0938e+03 -1.0942e+03 4e-01 1e-03 8e-04\n", 148 | "11: -1.0939e+03 -1.0940e+03 1e-01 7e-05 4e-05\n", 149 | "12: -1.0940e+03 -1.0940e+03 2e-02 1e-05 8e-06\n", 150 | "13: -1.0940e+03 -1.0940e+03 5e-03 1e-06 6e-07\n", 151 | "14: -1.0940e+03 -1.0940e+03 9e-04 1e-07 7e-08\n", 152 | "15: -1.0940e+03 -1.0940e+03 1e-04 2e-09 1e-09\n", 153 | "16: -1.0940e+03 -1.0940e+03 2e-05 4e-10 2e-10\n", 154 | "17: -1.0940e+03 -1.0940e+03 3e-06 7e-11 2e-11\n", 155 | "18: -1.0940e+03 -1.0940e+03 4e-07 6e-11 4e-12\n", 156 | "Optimal solution found.\n", 157 | " pcost dcost gap pres dres\n", 158 | " 0: -1.1703e+03 -1.1697e+03 4e+02 2e+01 1e+01\n", 159 | " 1: -1.1700e+03 -1.1868e+03 2e+01 8e-01 4e-01\n", 160 | " 2: -1.1718e+03 -1.1790e+03 7e+00 3e-01 2e-01\n", 161 | " 3: -1.1730e+03 -1.1799e+03 7e+00 3e-01 1e-01\n", 162 | " 4: -1.1755e+03 -1.1800e+03 4e+00 1e-01 7e-02\n", 163 | " 5: -1.1765e+03 -1.1811e+03 5e+00 1e-01 7e-02\n", 164 | " 6: -1.1791e+03 -1.1822e+03 3e+00 6e-02 3e-02\n", 165 | " 7: -1.1795e+03 -1.1825e+03 3e+00 5e-02 2e-02\n", 166 | " 8: -1.1804e+03 -1.1817e+03 1e+00 2e-02 9e-03\n", 167 | " 9: -1.1807e+03 -1.1817e+03 1e+00 8e-03 4e-03\n", 168 | "10: -1.1809e+03 -1.1811e+03 2e-01 1e-03 6e-04\n", 169 | "11: -1.1809e+03 -1.1811e+03 1e-01 3e-04 2e-04\n", 170 | "12: -1.1810e+03 -1.1810e+03 2e-02 5e-05 3e-05\n", 171 | "13: -1.1810e+03 -1.1810e+03 4e-03 5e-06 3e-06\n", 172 | "14: -1.1810e+03 -1.1810e+03 7e-04 4e-07 2e-07\n", 173 | "15: -1.1810e+03 -1.1810e+03 1e-04 4e-08 2e-08\n", 174 | "16: -1.1810e+03 -1.1810e+03 1e-05 4e-09 2e-09\n", 175 | "17: -1.1810e+03 -1.1810e+03 3e-06 5e-10 3e-10\n", 176 | "18: -1.1810e+03 -1.1810e+03 2e-07 7e-11 1e-11\n", 177 | "Optimal solution found.\n", 178 | " pcost dcost gap pres dres\n", 179 | " 0: -1.2766e+03 -1.2735e+03 5e+02 2e+01 1e+01\n", 180 | " 1: -1.2778e+03 -1.3289e+03 6e+01 3e+00 1e+00\n", 181 | " 2: -1.2866e+03 -1.3187e+03 3e+01 1e+00 5e-01\n", 182 | " 3: -1.2907e+03 -1.3060e+03 2e+01 3e-01 2e-01\n", 183 | " 4: -1.2947e+03 -1.3062e+03 1e+01 2e-01 1e-01\n", 184 | " 5: -1.2983e+03 -1.3060e+03 8e+00 9e-02 5e-02\n", 185 | " 6: -1.3000e+03 -1.3050e+03 5e+00 3e-02 1e-02\n", 186 | " 7: -1.3001e+03 -1.3036e+03 3e+00 1e-02 6e-03\n", 187 | " 8: -1.3004e+03 -1.3016e+03 1e+00 1e-03 6e-04\n", 188 | " 9: -1.3007e+03 -1.3012e+03 5e-01 1e-04 7e-05\n", 189 | "10: -1.3010e+03 -1.3011e+03 9e-02 1e-05 7e-06\n", 190 | "11: -1.3010e+03 -1.3010e+03 2e-02 2e-06 9e-07\n", 191 | "12: -1.3010e+03 -1.3010e+03 6e-03 2e-08 9e-09\n", 192 | "13: -1.3010e+03 -1.3010e+03 9e-04 2e-09 1e-09\n", 193 | "14: -1.3010e+03 -1.3010e+03 1e-04 2e-10 9e-11\n", 194 | "15: -1.3010e+03 -1.3010e+03 2e-05 7e-11 1e-11\n", 195 | "16: -1.3010e+03 -1.3010e+03 2e-06 7e-11 2e-12\n", 196 | "17: -1.3010e+03 -1.3010e+03 3e-07 7e-11 7e-12\n", 197 | "Optimal solution found.\n", 198 | " pcost dcost gap pres dres\n", 199 | " 0: -1.4052e+03 -1.4038e+03 5e+02 2e+01 1e+01\n", 200 | " 1: -1.4053e+03 -1.4357e+03 3e+01 2e+00 8e-01\n", 201 | " 2: -1.4114e+03 -1.4288e+03 2e+01 7e-01 3e-01\n", 202 | " 3: -1.4157e+03 -1.4289e+03 1e+01 4e-01 2e-01\n", 203 | " 4: -1.4216e+03 -1.4340e+03 1e+01 2e-01 1e-01\n", 204 | " 5: -1.4243e+03 -1.4294e+03 5e+00 7e-02 3e-02\n", 205 | " 6: -1.4254e+03 -1.4282e+03 3e+00 2e-02 1e-02\n", 206 | " 7: -1.4254e+03 -1.4280e+03 3e+00 2e-02 8e-03\n", 207 | " 8: -1.4258e+03 -1.4264e+03 6e-01 3e-03 1e-03\n", 208 | " 9: -1.4259e+03 -1.4264e+03 5e-01 2e-03 1e-03\n", 209 | "10: -1.4260e+03 -1.4261e+03 1e-01 5e-05 3e-05\n", 210 | "11: -1.4261e+03 -1.4261e+03 3e-02 7e-06 3e-06\n", 211 | "12: -1.4261e+03 -1.4261e+03 5e-03 8e-07 4e-07\n", 212 | "13: -1.4261e+03 -1.4261e+03 7e-04 6e-08 3e-08\n", 213 | "14: -1.4261e+03 -1.4261e+03 1e-04 4e-09 2e-09\n", 214 | "15: -1.4261e+03 -1.4261e+03 1e-05 4e-10 2e-10\n", 215 | "16: -1.4261e+03 -1.4261e+03 2e-06 7e-11 2e-11\n", 216 | "17: -1.4261e+03 -1.4261e+03 3e-07 6e-11 3e-12\n", 217 | "Optimal solution found.\n", 218 | " pcost dcost gap pres dres\n", 219 | " 0: -1.4847e+03 -1.4847e+03 5e+02 2e+01 1e+01\n", 220 | " 1: -1.4851e+03 -1.5095e+03 3e+01 1e+00 6e-01\n", 221 | " 2: -1.4880e+03 -1.4986e+03 1e+01 4e-01 2e-01\n", 222 | " 3: -1.4906e+03 -1.5011e+03 1e+01 4e-01 2e-01\n", 223 | " 4: -1.4932e+03 -1.4975e+03 4e+00 1e-01 6e-02\n", 224 | " 5: -1.4943e+03 -1.4984e+03 4e+00 9e-02 4e-02\n", 225 | " 6: -1.4957e+03 -1.4979e+03 2e+00 4e-02 2e-02\n", 226 | " 7: -1.4963e+03 -1.4983e+03 2e+00 2e-02 1e-02\n", 227 | " 8: -1.4967e+03 -1.4976e+03 9e-01 7e-03 3e-03\n", 228 | " 9: -1.4969e+03 -1.4974e+03 5e-01 1e-03 5e-04\n", 229 | "10: -1.4970e+03 -1.4971e+03 1e-01 1e-04 5e-05\n", 230 | "11: -1.4971e+03 -1.4971e+03 3e-02 2e-05 7e-06\n", 231 | "12: -1.4971e+03 -1.4971e+03 2e-02 9e-06 4e-06\n", 232 | "13: -1.4971e+03 -1.4971e+03 4e-03 1e-06 6e-07\n", 233 | "14: -1.4971e+03 -1.4971e+03 7e-04 1e-07 7e-08\n", 234 | "15: -1.4971e+03 -1.4971e+03 1e-04 2e-08 8e-09\n", 235 | "16: -1.4971e+03 -1.4971e+03 1e-05 2e-09 8e-10\n", 236 | "17: -1.4971e+03 -1.4971e+03 3e-06 3e-10 1e-10\n", 237 | "18: -1.4971e+03 -1.4971e+03 5e-07 7e-11 2e-11\n", 238 | "Optimal solution found.\n" 239 | ] 240 | } 241 | ], 242 | "source": [ 243 | "m, wd, eda_clean = process_statistical(eda, use_scipy=True, sample_rate=250, new_sample_rate=40, segment_width=10, segment_overlap=0)" 244 | ] 245 | }, 246 | { 247 | "cell_type": "markdown", 248 | "metadata": { 249 | "colab_type": "text", 250 | "id": "L1CxJWkTOmF3" 251 | }, 252 | "source": [ 253 | "# Working Data(wd) and Measures(m)\n", 254 | "process_statistical returns two dictionaries and a numpy array: Working Data(wd), Measures(m), and Clean EDA signal(eda_clean)\n", 255 | "
\n", 256 | "
\n", 257 | "\n", 258 | "Working Data(wd): This dictionary includes:\n", 259 | "
\n", 260 | "- filtered_phasic_gsr: phasic component of gsr signal passed from low pass filter for each window\n", 261 | "\n", 262 | "- phasic_gsr: phasic component of gsr signal for each window\n", 263 | "\n", 264 | "- tonic_gsr: tonic component of gsr signal for each window\n", 265 | "\n", 266 | "- peaklist: list of peaks for each window\n", 267 | "
\n", 268 | "\n", 269 | "Measures(m): This dictionary includes:\n", 270 | "
\n", 271 | "- number_of_peaks: number of peaks collected for each window\n", 272 | "\n", 273 | "- mean_gsr: mean of normalized gsr for each window\n", 274 | "\n", 275 | "- max_of_peaks: max of normalized gsr for each window\n", 276 | "
\n", 277 | "\n", 278 | "Clean EDA signal(eda_clean): This is a clean EDA signal after preprocessing" 279 | ] 280 | } 281 | ], 282 | "metadata": { 283 | "colab": { 284 | "name": "GSR Feature Extraction_notebook.ipynb", 285 | "provenance": [] 286 | }, 287 | "kernelspec": { 288 | "display_name": "Python 3", 289 | "language": "python", 290 | "name": "python3" 291 | }, 292 | "language_info": { 293 | "codemirror_mode": { 294 | "name": "ipython", 295 | "version": 3 296 | }, 297 | "file_extension": ".py", 298 | "mimetype": "text/x-python", 299 | "name": "python", 300 | "nbconvert_exporter": "python", 301 | "pygments_lexer": "ipython3", 302 | "version": "3.8.5" 303 | } 304 | }, 305 | "nbformat": 4, 306 | "nbformat_minor": 1 307 | } 308 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # Importing necessary libraries 2 | import matplotlib.pyplot as plt 3 | import numpy as np 4 | from sklearn.metrics import accuracy_score 5 | 6 | # Importing necessary functions for feature extraction 7 | from pyEDA.pyEDA.openShimmerFile import * 8 | from pyEDA.pyEDA.preprocessing import * 9 | from pyEDA.pyEDA.filtering import * 10 | from pyEDA.pyEDA.pyEDA import * 11 | from pyEDA.pyEDA.autoencoder import * 12 | 13 | def process_statistical(gsr_signal, use_scipy=True, sample_rate=128, new_sample_rate=40, segment_width=600, segment_overlap=0): 14 | gsrdata = np.array(gsr_signal) 15 | 16 | print("If you are using this tool for your research please cite this paper: \"pyEDA: An Open-Source Python Toolkit for Pre-processing and Feature Extraction of Electrodermal Activity\""); 17 | 18 | ################################################################################# 19 | ############################## Preprocessing Part ############################### 20 | 21 | # Resample the data based on original data rate of your device, here: 128Hz 22 | data = resample_data(gsrdata, sample_rate, new_sample_rate) 23 | 24 | # Segmentwise the data based on window sizes 25 | s_working_data, s_measures, gsrdata_segmentwise = segmentwise(data, sample_rate=new_sample_rate, segment_width=segment_width, segment_overlap=segment_overlap) 26 | 27 | preprocessed_gsr = [] 28 | for i in gsrdata_segmentwise: 29 | preprocessed_gsr.append(rolling_mean(i, 1./new_sample_rate, new_sample_rate)) 30 | 31 | ############################## Preprocessing Part ############################### 32 | ################################################################################# 33 | 34 | 35 | 36 | ################################################################################# 37 | ############################ Feature Extraction Part ############################ 38 | 39 | # Statistical Feature Extraction 40 | for i in preprocessed_gsr: 41 | working_data, measures = statistical_feature_extraction(i, new_sample_rate, use_scipy=use_scipy) 42 | for k in measures.keys(): 43 | s_measures = append_dict(s_measures, k, measures[k]) 44 | for k in working_data.keys(): 45 | s_working_data = append_dict(s_working_data, k, working_data[k]) 46 | 47 | wd = s_working_data 48 | m = s_measures 49 | 50 | ############################ Feature Extraction Part ############################ 51 | ################################################################################# 52 | 53 | return m, wd, preprocessed_gsr 54 | 55 | 56 | def prepare_automatic(gsr_signal, sample_rate=128, new_sample_rate=40, k=32, epochs=100, batch_size=10): 57 | gsrdata = np.array(gsr_signal) 58 | print("If you are using this tool for your research please cite this paper: \"pyEDA: An Open-Source Python Toolkit for Pre-processing and Feature Extraction of Electrodermal Activity\""); 59 | 60 | ################################################################################# 61 | ############################## Preprocessing Part ############################### 62 | 63 | # Resample the data based on original data rate of your device, here: 128Hz + rolling window 64 | 65 | preprocessed_gsr = [] 66 | for i in gsr_signal: 67 | data = resample_data(i, sample_rate, new_sample_rate) 68 | preprocessed_gsr.append(rolling_mean(data, 1./new_sample_rate, new_sample_rate)) 69 | preprocessed_gsr = np.array(preprocessed_gsr) 70 | 71 | ############################## Preprocessing Part ############################### 72 | ################################################################################# 73 | 74 | 75 | ################################################################################# 76 | ############################ Train the Autoencoder ############################## 77 | 78 | # set the input shape to model 79 | input_shape = preprocessed_gsr.shape[1] 80 | 81 | # use gpu if available 82 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 83 | 84 | # create a model from `AE` autoencoder class 85 | # load it to the specified device, either gpu or cpu 86 | model = AE(input_shape=input_shape, latent_size=k).to(device) 87 | 88 | # create an optimizer object 89 | # Adam optimizer with learning rate 1e-3 90 | optimizer = torch.optim.Adam(model.parameters(), lr=1e-3) 91 | 92 | # mean-squared error loss 93 | criterion = nn.MSELoss() 94 | 95 | # create tensor data 96 | train_loader = create_train_loader(preprocessed_gsr, batch_size) 97 | 98 | # Training the network 99 | for epoch in range(epochs): 100 | loss = 0 101 | for batch_features in train_loader: 102 | # reset the gradients back to zero 103 | # PyTorch accumulates gradients on subsequent backward passes 104 | optimizer.zero_grad() 105 | # compute reconstructions 106 | outputs,_ = model(batch_features) 107 | 108 | # compute training reconstruction loss 109 | train_loss = criterion(outputs, batch_features) 110 | 111 | # compute accumulated gradients 112 | train_loss.backward() 113 | 114 | # perform parameter update based on current gradients 115 | optimizer.step() 116 | 117 | # add the mini-batch training loss to epoch loss 118 | loss += train_loss.item() 119 | 120 | # compute the epoch training loss 121 | loss = loss / len(train_loader) 122 | 123 | # display the epoch training loss 124 | print("epoch : {}/{}, loss = {:.6f}".format(epoch + 1, epochs, loss)) 125 | 126 | # Save the network 127 | torch.save(model, 'pyEDA\pyEDA\checkpoint.t7') 128 | 129 | ############################ Train the Autoencoder ############################## 130 | ################################################################################# 131 | 132 | 133 | def process_automatic(gsr_signal): 134 | ################################################################################# 135 | ############################ Feature Extraction Part ############################ 136 | 137 | # Load the network 138 | model = torch.load('pyEDA\pyEDA\checkpoint.t7') 139 | 140 | # Extract the features 141 | gsr_signal = np.reshape(gsr_signal, (1, gsr_signal.shape[0])) 142 | train_outputs, latent_variable = model(torch.FloatTensor(gsr_signal)) 143 | return latent_variable.detach().numpy()[0]; 144 | 145 | ############################ Feature Extraction Part ############################ 146 | ################################################################################# 147 | 148 | -------------------------------------------------------------------------------- /pyEDA/__ init __.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__ init __.py -------------------------------------------------------------------------------- /pyEDA/__pycache__/DNN_Features.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/DNN_Features.cpython-38.pyc -------------------------------------------------------------------------------- /pyEDA/__pycache__/autoencoder.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/autoencoder.cpython-38.pyc -------------------------------------------------------------------------------- /pyEDA/__pycache__/calculateFeatures.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/calculateFeatures.cpython-38.pyc -------------------------------------------------------------------------------- /pyEDA/__pycache__/calculate_onSetOffSet.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/calculate_onSetOffSet.cpython-38.pyc -------------------------------------------------------------------------------- /pyEDA/__pycache__/calculate_thepeaks.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/calculate_thepeaks.cpython-38.pyc -------------------------------------------------------------------------------- /pyEDA/__pycache__/cvxEDA.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/cvxEDA.cpython-38.pyc -------------------------------------------------------------------------------- /pyEDA/__pycache__/filtering.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/filtering.cpython-38.pyc -------------------------------------------------------------------------------- /pyEDA/__pycache__/openShimmerFile.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/openShimmerFile.cpython-38.pyc -------------------------------------------------------------------------------- /pyEDA/__pycache__/preprocessing.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/preprocessing.cpython-38.pyc -------------------------------------------------------------------------------- /pyEDA/__pycache__/pyEDA.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/pyEDA.cpython-37.pyc -------------------------------------------------------------------------------- /pyEDA/__pycache__/pyEDA.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/pyEDA.cpython-38.pyc -------------------------------------------------------------------------------- /pyEDA/__pycache__/windowing.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/__pycache__/windowing.cpython-38.pyc -------------------------------------------------------------------------------- /pyEDA/autoencoder.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import numpy as np 3 | from torch import nn 4 | import math 5 | 6 | 7 | class AE(nn.Module): 8 | def __init__(self, **kwargs): 9 | super().__init__() 10 | closest_pow2 = pow(2,int(math.floor(math.log(kwargs["input_shape"],2)))) 11 | 12 | # Encoder layers 13 | self.linear1 = nn.Linear(in_features=kwargs["input_shape"], out_features=closest_pow2) 14 | self.conv1 = nn.Conv1d(1, 64, 3, padding=1) 15 | self.conv2 = nn.Conv1d(64, 32, 3, padding=1) 16 | self.conv3 = nn.Conv1d(32, 16, 3, padding=1) 17 | self.maxpool = nn.MaxPool1d(2, 2) 18 | self.linear2 = nn.Linear(in_features=(closest_pow2)*2, out_features=kwargs["latent_size"]) 19 | 20 | # Decoder layers 21 | self.linear3 = nn.Linear(in_features=kwargs["latent_size"], out_features=(closest_pow2)*2) 22 | self.deconv1 = nn.ConvTranspose1d(16, 32, 2, stride=2) 23 | self.deconv2 = nn.ConvTranspose1d(32, 64, 2, stride=2) 24 | self.deconv3 = nn.ConvTranspose1d(64, 1, 2, stride=2) 25 | self.linear4 = nn.Linear(in_features=closest_pow2, out_features=kwargs["input_shape"]) 26 | 27 | 28 | def forward(self, features): 29 | # Encoder 30 | activation = self.linear1(features) 31 | activation = torch.reshape(activation, (activation.shape[0],1,activation.shape[1])) 32 | activation = self.conv1(activation) 33 | activation = torch.relu(activation) 34 | activation = self.maxpool(activation) 35 | activation = self.conv2(activation) 36 | activation = torch.relu(activation) 37 | activation = self.maxpool(activation) 38 | activation = self.conv3(activation) 39 | activation = torch.relu(activation) 40 | activation = self.maxpool(activation) 41 | d = activation.shape 42 | activation = torch.reshape(activation, (d[0],d[1]*d[2])) 43 | code = self.linear2(activation) 44 | 45 | # Decoder 46 | activation = self.linear3(code) 47 | activation = torch.reshape(activation, (d[0],d[1],d[2])) 48 | activation = self.deconv1(activation) 49 | activation = torch.relu(activation) 50 | activation = self.deconv2(activation) 51 | activation = torch.relu(activation) 52 | activation = self.deconv3(activation) 53 | activation = torch.sigmoid(activation) 54 | activation = torch.reshape(activation, (activation.shape[0],activation.shape[2])) 55 | reconstructed = self.linear4(activation) 56 | 57 | return reconstructed, code 58 | 59 | 60 | def create_train_loader(gsrData, batch_size=10): 61 | train_loader = [] 62 | tensor_data = [] 63 | 64 | for data in gsrData: 65 | tensor_data.append(np.array(data).flatten()) 66 | if (len(tensor_data) == batch_size): 67 | train_loader.append(tensor_data) 68 | tensor_data = [] 69 | 70 | if (len(tensor_data) != 0): 71 | print("Train data concatenated due to incompatible batch_size!") 72 | 73 | return torch.FloatTensor(train_loader) -------------------------------------------------------------------------------- /pyEDA/calculateFeatures.py: -------------------------------------------------------------------------------- 1 | # Importing necessary libraries 2 | import numpy as np 3 | 4 | def calculate_max_peaks(data): 5 | '''maximum of the peaks 6 | Funcion that finds the maximum of the peaks 7 | 8 | Parameters 9 | ---------- 10 | data : 1-d array 11 | array containing set of peaks 12 | 13 | Returns 14 | ------- 15 | max(data) : int or float 16 | maximum value of the peak 17 | ''' 18 | if (len(data) == 0): 19 | return 0 20 | else: 21 | return np.max(data) 22 | 23 | def calculate_mean_gsr(data): 24 | '''mean of the gsr data 25 | Funcion that finds the mean of the gsr data 26 | 27 | Parameters 28 | ---------- 29 | data : 1-d array 30 | array containing gsr data 31 | 32 | Returns 33 | ------- 34 | mean(data) : int or float 35 | mean value of the gsr data 36 | ''' 37 | return np.mean(data) 38 | 39 | def calculate_number_of_peaks(data): 40 | '''number of the peaks 41 | Funcion that finds the number of the peaks 42 | 43 | Parameters 44 | ---------- 45 | data : 1-d array 46 | array containing set of peaks 47 | 48 | Returns 49 | ------- 50 | max(data) : int 51 | number of the peak 52 | ''' 53 | return len(data) -------------------------------------------------------------------------------- /pyEDA/calculate_onSetOffSet.py: -------------------------------------------------------------------------------- 1 | # Importing necessary libraries 2 | import numpy as np 3 | 4 | ''' 5 | Calculate the list of on-sets and off-sets based on phasic component of signal. 6 | ''' 7 | def calculate_onSetOffSet(phasic_gsr, sample_rate, minDiff=0.5, onSetThreshold=0.01): 8 | '''finding on-sets and off-sets 9 | Funcion that finds the on-sets and offsets of gsr data using phasic component 10 | 11 | Parameters 12 | ---------- 13 | phasic_gsr : 1-d array 14 | array containing phasic component of gsr 15 | sample_rate : int or float 16 | sample rate of the data stream in 'data' 17 | minDiff : float 18 | minimum acceptable time difference between on-set and off-set 19 | default : 0.02 20 | onSetThreshold : float 21 | on set threshold 22 | default : 0.02 23 | 24 | Returns 25 | ------- 26 | peaklist : 2-d array 27 | list of peaks for each onSet-offSet window 28 | indexlist : 2-d array 29 | list of indexes peaks for each onSet-offSet window 30 | ''' 31 | # Some initializations 32 | onSet_offSet = [] 33 | tmpSet = [] 34 | onIsSet = False 35 | 36 | for i, data in enumerate(phasic_gsr): 37 | if (onIsSet): 38 | if (data < 0): 39 | tmpSet.append(i) 40 | timeDifference = tmpSet[1]-tmpSet[0] 41 | timeDifference = timeDifference/sample_rate 42 | if (timeDifference > minDiff): 43 | onSet_offSet.append(tmpSet) 44 | tmpSet = [] 45 | onIsSet = False 46 | elif data > onSetThreshold: 47 | tmpSet.append(i) 48 | onIsSet = True 49 | 50 | return np.array(onSet_offSet) -------------------------------------------------------------------------------- /pyEDA/calculate_thepeaks.py: -------------------------------------------------------------------------------- 1 | # Importing necessary libraries 2 | import numpy as np 3 | 4 | ''' 5 | Calculate the number of peaks based on on-set and off-set values. 6 | ''' 7 | def calculate_thepeaks(gsr, onSet_offSet, ampThreshold=0.02): 8 | '''calculate the peaks 9 | Funcion that finds the peaks in each on-set off-set window 10 | 11 | Parameters 12 | ---------- 13 | gsr : 1-d array 14 | array containing gsr sensor data 15 | onSet_offSet : 2-d array 16 | array containing the onSet and offSet for each window 17 | ampThreshold : float 18 | amplitude threshold 19 | default : 0.02 20 | 21 | Returns 22 | ------- 23 | peaklist : 2-d array 24 | list of peaks for each onSet-offSet window 25 | indexlist : 2-d array 26 | list of indexes peaks for each onSet-offSet window 27 | ''' 28 | # Some initializations 29 | peaklist = [] 30 | indexlist = [] 31 | checkForMax = False 32 | peakIndex = 0 33 | index = 0 34 | Max = 0 35 | 36 | for i, data in enumerate(gsr): 37 | if (index == len(onSet_offSet)): 38 | break 39 | if (checkForMax): 40 | startIndex = onSet_offSet[index][0] 41 | amplitude = data-gsr[startIndex] 42 | if (amplitude > Max): 43 | peakIndex = i 44 | Max = amplitude 45 | if (i == onSet_offSet[index][1]): 46 | # Check the threshold and add the peak to peaklist 47 | if (Max > ampThreshold): 48 | peaklist.append(Max) 49 | indexlist.append(peakIndex) 50 | Max = 0 51 | checkForMax = False 52 | index=index+1 53 | elif (i == onSet_offSet[index][0]): 54 | checkForMax = True 55 | 56 | return np.array(peaklist), np.array(indexlist) -------------------------------------------------------------------------------- /pyEDA/checkpoint.t7: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HealthSciTech/pyEDA/e664ecdd394435095d4b18c0c499ed9a5d371f4c/pyEDA/checkpoint.t7 -------------------------------------------------------------------------------- /pyEDA/cvxEDA.py: -------------------------------------------------------------------------------- 1 | """ 2 | ______________________________________________________________________________ 3 | 4 | File: cvxEDA.py 5 | Last revised: 07 Nov 2015 r69 6 | ______________________________________________________________________________ 7 | 8 | Copyright (C) 2014-2015 Luca Citi, Alberto Greco 9 | 10 | This program is free software; you can redistribute it and/or modify it under 11 | the terms of the GNU General Public License as published by the Free Software 12 | Foundation; either version 3 of the License, or (at your option) any later 13 | version. 14 | 15 | This program is distributed in the hope that it will be useful, but WITHOUT 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 18 | 19 | You may contact the author by e-mail (lciti@ieee.org). 20 | ______________________________________________________________________________ 21 | 22 | This method was first proposed in: 23 | A Greco, G Valenza, A Lanata, EP Scilingo, and L Citi 24 | "cvxEDA: a Convex Optimization Approach to Electrodermal Activity Processing" 25 | IEEE Transactions on Biomedical Engineering, 2015 26 | DOI: 10.1109/TBME.2015.2474131 27 | 28 | If you use this program in support of published research, please include a 29 | citation of the reference above. If you use this code in a software package, 30 | please explicitly inform the end users of this copyright notice and ask them 31 | to cite the reference above in their published research. 32 | ______________________________________________________________________________ 33 | """ 34 | 35 | # Importing necessary libraries 36 | import numpy as np 37 | import cvxopt as cv 38 | import cvxopt.solvers 39 | 40 | def cvxEDA(y, delta, tau0=2., tau1=0.7, delta_knot=10., alpha=8e-4, gamma=1e-2, 41 | solver=None, options={'reltol':1e-9}): 42 | """CVXEDA Convex optimization approach to electrodermal activity processing 43 | 44 | This function implements the cvxEDA algorithm described in "cvxEDA: a 45 | Convex Optimization Approach to Electrodermal Activity Processing" 46 | (http://dx.doi.org/10.1109/TBME.2015.2474131, also available from the 47 | authors' homepages). 48 | 49 | Arguments: 50 | y: observed EDA signal (we recommend normalizing it: y = zscore(y)) 51 | delta: sampling interval (in seconds) of y 52 | tau0: slow time constant of the Bateman function 53 | tau1: fast time constant of the Bateman function 54 | delta_knot: time between knots of the tonic spline function 55 | alpha: penalization for the sparse SMNA driver 56 | gamma: penalization for the tonic spline coefficients 57 | solver: sparse QP solver to be used, see cvxopt.solvers.qp 58 | options: solver options, see: 59 | http://cvxopt.org/userguide/coneprog.html#algorithm-parameters 60 | 61 | Returns (see paper for details): 62 | r: phasic component 63 | p: sparse SMNA driver of phasic component 64 | t: tonic component 65 | l: coefficients of tonic spline 66 | d: offset and slope of the linear drift term 67 | e: model residuals 68 | obj: value of objective function being minimized (eq 15 of paper) 69 | """ 70 | 71 | n = len(y) 72 | y = cv.matrix(y) 73 | 74 | # bateman ARMA model 75 | a1 = 1./min(tau1, tau0) # a1 > a0 76 | a0 = 1./max(tau1, tau0) 77 | ar = np.array([(a1*delta + 2.) * (a0*delta + 2.), 2.*a1*a0*delta**2 - 8., 78 | (a1*delta - 2.) * (a0*delta - 2.)]) / ((a1 - a0) * delta**2) 79 | ma = np.array([1., 2., 1.]) 80 | 81 | # matrices for ARMA model 82 | i = np.arange(2, n) 83 | A = cv.spmatrix(np.tile(ar, (n-2,1)), np.c_[i,i,i], np.c_[i,i-1,i-2], (n,n)) 84 | M = cv.spmatrix(np.tile(ma, (n-2,1)), np.c_[i,i,i], np.c_[i,i-1,i-2], (n,n)) 85 | 86 | # spline 87 | delta_knot_s = int(round(delta_knot / delta)) 88 | spl = np.r_[np.arange(1.,delta_knot_s), np.arange(delta_knot_s, 0., -1.)] # order 1 89 | spl = np.convolve(spl, spl, 'full') 90 | spl /= max(spl) 91 | # matrix of spline regressors 92 | i = np.c_[np.arange(-(len(spl)//2), (len(spl)+1)//2)] + np.r_[np.arange(0, n, delta_knot_s)] 93 | nB = i.shape[1] 94 | j = np.tile(np.arange(nB), (len(spl),1)) 95 | p = np.tile(spl, (nB,1)).T 96 | valid = (i >= 0) & (i < n) 97 | B = cv.spmatrix(p[valid], i[valid], j[valid]) 98 | 99 | # trend 100 | C = cv.matrix(np.c_[np.ones(n), np.arange(1., n+1.)/n]) 101 | nC = C.size[1] 102 | 103 | # Solve the problem: 104 | # .5*(M*q + B*l + C*d - y)^2 + alpha*sum(A,1)*p + .5*gamma*l'*l 105 | # s.t. A*q >= 0 106 | 107 | old_options = cv.solvers.options.copy() 108 | cv.solvers.options.clear() 109 | cv.solvers.options.update(options) 110 | if solver == 'conelp': 111 | # Use conelp 112 | z = lambda m,n: cv.spmatrix([],[],[],(m,n)) 113 | G = cv.sparse([[-A,z(2,n),M,z(nB+2,n)],[z(n+2,nC),C,z(nB+2,nC)], 114 | [z(n,1),-1,1,z(n+nB+2,1)],[z(2*n+2,1),-1,1,z(nB,1)], 115 | [z(n+2,nB),B,z(2,nB),cv.spmatrix(1.0, range(nB), range(nB))]]) 116 | h = cv.matrix([z(n,1),.5,.5,y,.5,.5,z(nB,1)]) 117 | c = cv.matrix([(cv.matrix(alpha, (1,n)) * A).T,z(nC,1),1,gamma,z(nB,1)]) 118 | res = cv.solvers.conelp(c, G, h, dims={'l':n,'q':[n+2,nB+2],'s':[]}) 119 | obj = res['primal objective'] 120 | else: 121 | # Use qp 122 | Mt, Ct, Bt = M.T, C.T, B.T 123 | H = cv.sparse([[Mt*M, Ct*M, Bt*M], [Mt*C, Ct*C, Bt*C], 124 | [Mt*B, Ct*B, Bt*B+gamma*cv.spmatrix(1.0, range(nB), range(nB))]]) 125 | f = cv.matrix([(cv.matrix(alpha, (1,n)) * A).T - Mt*y, -(Ct*y), -(Bt*y)]) 126 | res = cv.solvers.qp(H, f, cv.spmatrix(-A.V, A.I, A.J, (n,len(f))), 127 | cv.matrix(0., (n,1)), solver=solver) 128 | obj = res['primal objective'] + .5 * (y.T * y) 129 | cv.solvers.options.clear() 130 | cv.solvers.options.update(old_options) 131 | 132 | l = res['x'][-nB:] 133 | d = res['x'][n:n+nC] 134 | t = B*l + C*d 135 | q = res['x'][:n] 136 | p = A * q 137 | r = M * q 138 | e = y - r - t 139 | 140 | return (np.array(a).ravel() for a in (r, p, t, l, d, e, obj)) -------------------------------------------------------------------------------- /pyEDA/filtering.py: -------------------------------------------------------------------------------- 1 | # Importing necessary libraries 2 | from scipy.signal import butter, filtfilt 3 | 4 | ''' 5 | Low pass filter to remove noise specially artifact noise 6 | ''' 7 | def butter_lowpassfilter(data, cutoff, sample_rate, order=2): 8 | '''standard lowpass filter. 9 | Function that filters the data using standard Butterworth lowpass filter 10 | 11 | Parameters 12 | ---------- 13 | data : 1-d array 14 | array containing the gsr data 15 | cutoff : int or float 16 | frequency in Hz that acts as cutoff for filter. 17 | sample_rate : int or float 18 | sample rate of the supplied signal 19 | order : int 20 | filter order, defines the strength of the roll-off 21 | around the cutoff frequency. 22 | default: 2 23 | 24 | Returns 25 | ------- 26 | y : 1-d array 27 | filtered gsr data 28 | ''' 29 | nyq = 0.5 * sample_rate 30 | normal_cutoff = cutoff/nyq 31 | b, a = butter(order, normal_cutoff, btype='low', analog=False) 32 | y = filtfilt(b, a, data) 33 | return y -------------------------------------------------------------------------------- /pyEDA/openShimmerFile.py: -------------------------------------------------------------------------------- 1 | # Importing necessary libraries 2 | import csv 3 | 4 | def openShimmerFile(url, column_name): 5 | '''finding to open the files 6 | Funcion that extracts gsr data from the files 7 | 8 | Parameters 9 | ---------- 10 | url : String 11 | The address of the csv file from Shimmer 12 | column_name : String 13 | The name of the column to extract its data from the file 14 | 15 | Returns 16 | ------- 17 | req_data : 1-d array 18 | Array containing the gsr data 19 | ''' 20 | 21 | req_data = [] 22 | index = -1 23 | 24 | # Read File 25 | with open(url) as f: 26 | if ('csv' in url): 27 | reader = csv.reader(f, delimiter=',') 28 | else: 29 | reader = csv.reader(f, delimiter='\t') 30 | # Store data in lists 31 | sep = reader.__next__() 32 | sep = reader.__next__() 33 | sep = reader.__next__() 34 | forth_row = reader.__next__() 35 | shimmer_header = [] 36 | data_header = [] 37 | calib_header = [] 38 | for i,column in enumerate(forth_row): 39 | if (column == column_name): 40 | index = i 41 | reader.__next__() 42 | 43 | if (index < 0): 44 | print("Column not found!") 45 | 46 | for row in reader: 47 | if (index <= len(row)): 48 | req_data.append(float(row[index])) 49 | 50 | return req_data -------------------------------------------------------------------------------- /pyEDA/preprocessing.py: -------------------------------------------------------------------------------- 1 | # Importing necessary libraries 2 | import numpy as np 3 | import scipy.signal as sps 4 | 5 | 6 | def resample_data(gsrdata, prevSR, newSR): 7 | '''calculates rolling mean 8 | Function to calculate moving average over the passed data 9 | 10 | Parameters 11 | ---------- 12 | gsrdata : 1-d array 13 | array containing the gsr data 14 | prevSR : int or float 15 | the previous sample rate of the data 16 | newSR : int or float 17 | the new sample rate of the data 18 | 19 | Returns 20 | ------- 21 | data : 1-d array 22 | array containing the resampled data 23 | ''' 24 | number_of_samples = int(round(len(gsrdata) * float(newSR) / prevSR)) 25 | data = sps.resample(gsrdata, number_of_samples) 26 | 27 | return data 28 | 29 | 30 | def normalization(gsrdata): 31 | '''min max normalization 32 | Function to calculate normalized gsr data 33 | 34 | Parameters 35 | ---------- 36 | gsrdata : 1-d array 37 | array containing the gsr data 38 | 39 | Returns 40 | ------- 41 | n_gsrdata : 1-d array 42 | normalized gsr data 43 | ''' 44 | gsrdata = gsrdata-(np.min(gsrdata)) 45 | gsrdata /= (np.max(gsrdata) - np.min(gsrdata)) 46 | n_gsrdata = gsrdata 47 | return n_gsrdata 48 | 49 | def rolling_mean(data, windowsize, sample_rate): 50 | '''calculates rolling mean 51 | Function to calculate moving average over the passed data 52 | 53 | Parameters 54 | ---------- 55 | data : 1-d array 56 | array containing the gsr data 57 | windowsize : int or float 58 | the moving average window size in seconds 59 | sample_rate : int or float 60 | the sample rate of the data set 61 | 62 | Returns 63 | ------- 64 | rol_mean : 1-d array 65 | array containing computed rolling mean 66 | ''' 67 | avg_hr = (np.mean(data)) 68 | data_arr = np.array(data) 69 | 70 | t_windowsize = int(windowsize*sample_rate) 71 | t_shape = data_arr.shape[:-1] + (data_arr.shape[-1] - t_windowsize + 1, t_windowsize) 72 | t_strides = data_arr.strides + (data_arr.strides[-1],) 73 | sep_win = np.lib.stride_tricks.as_strided(data_arr, shape=t_shape, strides=t_strides) 74 | rol_mean = np.mean(sep_win, axis=1) 75 | 76 | missing_vals = np.array([avg_hr for i in range(0, int(abs(len(data_arr) - len(rol_mean))/2))]) 77 | rol_mean = np.insert(rol_mean, 0, missing_vals) 78 | rol_mean = np.append(rol_mean, missing_vals) 79 | 80 | #only to catch length errors that sometimes unexplicably occur. 81 | ##Generally not executed, excluded from testing and coverage 82 | if len(rol_mean) != len(data): # pragma: no cover 83 | lendiff = len(rol_mean) - len(data) 84 | if lendiff < 0: 85 | rol_mean = np.append(rol_mean, 0) 86 | else: 87 | rol_mean = rol_mean[:-1] 88 | 89 | return rol_mean -------------------------------------------------------------------------------- /pyEDA/pyEDA.py: -------------------------------------------------------------------------------- 1 | # Importing necessary libraries 2 | import numpy as np 3 | import time 4 | import scipy.signal 5 | import matplotlib.pyplot as plt 6 | from scipy import stats 7 | 8 | # Importing necessary functions 9 | from pyEDA.pyEDA.calculate_onSetOffSet import * 10 | from pyEDA.pyEDA.calculate_thepeaks import * 11 | from pyEDA.pyEDA.calculateFeatures import * 12 | from pyEDA.pyEDA.cvxEDA import * 13 | from pyEDA.pyEDA.filtering import * 14 | from pyEDA.pyEDA.preprocessing import * 15 | from pyEDA.pyEDA.windowing import * 16 | 17 | ''' 18 | 19 | ''' 20 | def statistical_feature_extraction(preprocessed_gsr, sample_rate, windowsize=0.75, use_scipy=True, measures={}, 21 | working_data={}): 22 | '''processes passed gsrdata. 23 | 24 | Processes the passed gsr data. Returns measures{} dict containing results. 25 | Parameters 26 | ---------- 27 | preprocessed_gsr : 1d array or list 28 | array or list containing normalized gsr data to be analysed 29 | sample_rate : int or float 30 | the sample rate with which the gsr data is sampled 31 | windowsize : int or float 32 | the window size in seconds to use in the calculation of the moving average. 33 | Calculated as windowsize * sample_rate 34 | default : 0.75 35 | measures : dict 36 | dictionary object used by heartpy to store computed measures. Will be created 37 | if not passed to function. 38 | working_data : dict 39 | dictionary object that contains all heartpy's working data (temp) objects. 40 | will be created if not passed to function 41 | Returns 42 | ------- 43 | working_data : dict 44 | dictionary object used to store temporary values. 45 | 46 | measures : dict 47 | dictionary object used by heartpy to store computed measures. 48 | ''' 49 | t1 = time.time() 50 | 51 | 52 | # Extracting phasic and tonic components of from normalized gsr 53 | [phasic_gsr, p, tonic_gsr, l, d, e, obj] = cvxEDA(preprocessed_gsr, 1./sample_rate) 54 | 55 | # Removing line noise 56 | filtered_phasic_gsr = phasic_gsr # comment out the next line if the line noise in negligble in your data 57 | filtered_phasic_gsr = butter_lowpassfilter(phasic_gsr, 5./sample_rate, sample_rate, order=4) 58 | 59 | # Update working_data 60 | working_data['filtered_phasic_gsr'] = filtered_phasic_gsr 61 | working_data['phasic_gsr'] = phasic_gsr 62 | working_data['tonic_gsr'] = tonic_gsr 63 | 64 | peaklist = [] 65 | indexlist = [] 66 | 67 | if (use_scipy): 68 | indexlist, _ = scipy.signal.find_peaks(filtered_phasic_gsr) 69 | for i in indexlist: 70 | peaklist.append(preprocessed_gsr[i]) 71 | else: 72 | # Calculate the onSet and offSet based on Phasic GSR signal 73 | onSet_offSet = calculate_onSetOffSet(filtered_phasic_gsr, sample_rate) 74 | # Calculate the peaks using onSet and offSet of Phasic GSR signal 75 | if (len(onSet_offSet) != 0): 76 | peaklist, indexlist = calculate_thepeaks(preprocessed_gsr, onSet_offSet) 77 | 78 | working_data['peaklist'] = peaklist 79 | working_data['indexlist'] = indexlist 80 | # Calculate the number of peaks 81 | measures['number_of_peaks'] = calculate_number_of_peaks(peaklist) 82 | # Calculate the std mean of EDA 83 | measures['mean_gsr'] = calculate_mean_gsr(preprocessed_gsr) 84 | # Calculate the maximum value of peaks of EDA 85 | measures['max_of_peaks'] = calculate_max_peaks(peaklist) 86 | 87 | return working_data, measures 88 | 89 | 90 | 91 | ''' 92 | process EDA signal with windowing of size segment_width*sample_rate 93 | ''' 94 | def segmentwise(gsrdata, sample_rate, segment_width=120, segment_overlap=0, 95 | segment_min_size=5): 96 | '''processes passed gsrdata. 97 | Processes the passed gsr data. Returns measures{} dict containing results. 98 | 99 | Parameters 100 | ---------- 101 | gsrdata : 1d array or list 102 | array or list containing gsr data to be analysed 103 | sample_rate : int or float 104 | the sample rate with which the gsr data is sampled 105 | segment_width : int or float 106 | width of segments in seconds 107 | default : 120 108 | segment_overlap: float 109 | overlap fraction of adjacent segments. 110 | Needs to be 0 <= segment_overlap < 1. 111 | default : 0 (no overlap) 112 | segment_min_size : int 113 | often a tail end of the data remains after segmenting into segments. 114 | default : 20 115 | 116 | Returns 117 | ------- 118 | gsrdata_segmentwise : 2d array or list 119 | array or list containing segmentwised gsr data to be analysed 120 | orking_data : dict 121 | dictionary object used to store temporary values. 122 | s_measures : dict 123 | dictionary object used by heartpy to store computed measures. 124 | ''' 125 | slice_indices = make_windows(gsrdata, sample_rate, segment_width, segment_overlap, segment_min_size) 126 | 127 | s_measures = {} 128 | s_working_data = {} 129 | 130 | gsrdata_segmentwise = [] 131 | for i, ii in slice_indices: 132 | gsrdata_segmentwise.append(gsrdata[i:ii]) 133 | s_measures = append_dict(s_measures, 'segment_indices', (i, ii)) 134 | s_working_data = append_dict(s_working_data, 'segment_indices', (i, ii)) 135 | return s_working_data, s_measures, gsrdata_segmentwise 136 | -------------------------------------------------------------------------------- /pyEDA/windowing.py: -------------------------------------------------------------------------------- 1 | # Importing necessary libraries 2 | import numpy as np 3 | 4 | def make_windows(data, sample_rate, windowsize=120, overlap=0, min_size=5): 5 | '''slices data into windows 6 | Funcion that slices data into windows. 7 | 8 | Parameters 9 | ---------- 10 | data : 1-d array 11 | array containing gsr data 12 | sample_rate : int or float 13 | sample rate of the data stream in 'data' 14 | windowsize : int 15 | size of the window that is sliced in seconds 16 | overlap : float 17 | fraction of overlap between two adjacent windows: 0 <= float < 1.0 18 | min_size : int 19 | the minimum size for the last (partial) window to be included. 20 | 21 | Returns 22 | ------- 23 | out : array 24 | tuples of window indices 25 | ''' 26 | ln = len(data) 27 | window = windowsize * sample_rate 28 | stepsize = (1 - overlap) * window 29 | start = 0 30 | end = window 31 | 32 | slices = [] 33 | while end < len(data): 34 | slices.append((start, end)) 35 | start += stepsize 36 | end += stepsize 37 | 38 | if min_size == -1: 39 | slices[-1] = (slices[-1][0], len(data)) 40 | elif (ln - start) / sample_rate >= min_size: 41 | slices.append((start, ln)) 42 | 43 | return np.array(slices, dtype=np.int32) 44 | 45 | 46 | def append_dict(dict, key, value): 47 | '''appends data to dict. 48 | Function that appends key to dict, if doesn't exist. 49 | 50 | Parameters 51 | ---------- 52 | dict : dictionary 53 | dictionary object that contains continuous output measures 54 | key : String 55 | key for the measure to be stored in continuous_dict 56 | value : any data container 57 | value to be appended to dictionary 58 | 59 | Returns 60 | ------- 61 | dict : dict 62 | dictionary object passed to function, with specified data container appended 63 | ''' 64 | try: 65 | dict[key].append(value) 66 | except KeyError: 67 | dict[key] = [value] 68 | return dict --------------------------------------------------------------------------------