├── .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": "iVBORw0KGgoAAAANSUhEUgAAAskAAAD4CAYAAAAejHvMAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/d3fzzAAAACXBIWXMAAAsTAAALEwEAmpwYAABjJUlEQVR4nO3dd3xb9bn48c9X8t5723GcOHsvAiGBMBOghE1CWyhllBZ6S0vn7e+293b39pa2tLSUQstomQUKBcJeYWXv7SRO7HhPyUPy0Pf3h6RgHDuW7XO0/LxfL7/inHMsfa1jSY++5/k+j9JaI4QQQgghhPiEJdADEEIIIYQQIthIkCyEEEIIIUQ/EiQLIYQQQgjRjwTJQgghhBBC9CNBshBCCCGEEP1EBHoAA8nIyNDFxcWBHoYQQgghhAhjmzdvbtBaZw60LyiD5OLiYjZt2hToYQghhBBCiDCmlDo62D5JtxBCCCGEEKIfCZKFEEIIIYToR4JkIYQQQggh+pEgWQghhBBCiH4kSBZCCCGEEKIfCZKFEEIIIYToR4JkIYQQQggh+pEgWQghhBBCDFtPr4t/bq7k39ur0FoHejiGC8pmIkIIIYQQIrj96MU9PPKRuxfH7iob3105JcAjMpYEyUIIIYQQYliONLTz94+P8rnFRXT1uLj/vUNcMiuXGfnJgR6aYSTdQgghhBBCDMvz246jgf84p5TvXzyNhOgI/vTuoUAPy1ASJAshhBDCFFprHv6wnK8/uY09VbZAD0cYaO3OGhaOSyMrKYbk2EjWLCrilV011LQ6Aj00w0iQLITwm52Vrdz9+gHK6uyBHooQwg/+ubmSH76wm+e2Hue6Bz4OqwBqLKuzOdhfa+fcqVkntq1ZVESvS/PC9uMBHJmxJEgWQvjFofo2rrrvQ+558yCX3fsh5Q3tgR6SEMJEWmv+9M4hZhck8+ZdZ9Hh7OV3bx4I9LCEAbYcawZgQXHaiW3FGfHMKUzhua1VgRqW4SRIFkL4xT1vHiTSauGZL5+BAn728t5AD0kIYaJNR5s53NDO508vZkJmAmsWFfLUpkrqbDKbHOq2HGshymphRn7Sp7ZfNiePvdU2yuraAjQyY0mQLIQwXbuzh7U7a7hyXj7zx6Vy89ISXttTy74ayVEUIly9ubeOCIti5YwcAG44o5hel+afWyoDPDIxWtsqWpiWl0R0hPVT2y+Y7j7Xb+ytDcSwDCdBshDCdB8eaqSr18WFnhfQ608fR5TVwpMbKwI8MiGEWT463MicwhTio93VZksyE1hUnMZTGyvCsvHEWKG15kCtnam5iSfty0uJZXpeEm/sGSNBslKqUCn1tlJqr1Jqt1LqawMc8y2l1DbP1y6lVK9SKs2zr1wptdOzb5MZv4QQIri9vb+O+Cjrify11Pgozp+Wzb+2HqerxxXg0QkhjNbm7GHX8VZOn5D+qe1XzMunvLGD3VLpImQ1tHXR0tHNxKyTg2SA86Zms/lYM41tTj+PzHi+zCT3AHdpracCi4HblVLT+h6gtf6V1nqO1noO8D3gXa11U59Dlnv2LzBq4EKI0LHlaDPzi9OIivjkJefK+fk0d3Tzfll9AEcmhDDDvmobvS7N3KKUT20/f1o2FgWv7q4JzMDEqB30VCealJ0w4P7zp2WjNby1r86fwzLFkEGy1rpaa73F870d2Avkn+JH1gCPGzM8IUSo6+jq4UCtnTkFn+7CtGRiBgnREbweJpflhBCf2FvtnimemvvphV3pCdEsGp8mQXII8y7KKx1kJnl6XhK5yTFh8do+rJxkpVQxMBdYP8j+OGAF8EyfzRp4TSm1WSl16ylu+1al1Cal1Kb6eplZEiJc7K6y4dIwqyDlU9ujI6ycPTmT1/fU0uuS/EQhwsneGjvJsZHkJMWctO/C6TkcqG3jUH14VEAYaw7WtpEYHUF2UvSA+5VSnDs1i/fLGnD29Pp5dMbyOUhWSiXgDn7v1FoPlkz0GeCDfqkWS7TW84CVuFM1lg30g1rr+7XWC7TWCzIzM30dlhAiyO0+3grAzH4zyeBeCd3Q1sW2imZ/D0sIYaK91Tam5CSilDppn3cBr8wmh6bDDW2UZCUMeG69zpmSRUdXL+sPNw16TCjwKUhWSkXiDpD/obV+9hSHrqZfqoXWusrzbx3wHLBoZEMVQoSisvo2kmIiyEo8edbh7MmZRFoVr+0O/ctyQgg3l0uzv8Z+UqqFV15KLDPyk3hzb+jnrI5F1S0OClJiT3nM6SUZREdYQj4v2ZfqFgp4ENirtb77FMclA2cBz/fZFq+USvR+D1wA7BrtoIUQoeNQXTsTBpl1SIqJZNH4NN7ZLylWQoSLqtZOOrp6KR1kYRe4KyBsOdZMQxhUQBhLtNZUtXaSk3xyGk1fsVFWzpiQzlv76kK63J8vM8lLgM8D5/Qp83aRUuo2pdRtfY67HHhNa92312w28L5SajuwAXhJa/2KYaMXQgS9Q/VtTMgc/M1yWWkm+2vt1EoXLiHCwtHGDgDGp8cPekw4VUAYS1o7u3F0u8gdIkgGOGdqNseaOjhU3z7kscHKl+oW72utldZ6lrfMm9b6Za31fVrr+/oc95DWenW/nz2stZ7t+Zqutf6pGb+EECI42Rzd1NmdpwySl5a61yC8d0Bmk4UIB94geVzG4EHytNwk8pJjwqbpxFhR1eKezMhNPnW6BbjzkgHeDuEPQtJxTwhhmkOeUkETMgd/s5yam0hmYjTvHWzw17CEECY62thOlNUyYGULL6UU503LZt3BBhzdoV0BYSypsXUCkJsy9Exyfkosk7MTeXNf6H4QkiBZCGGaw57LbBOyBp9JVkqxtDSD9w/WSyk4IcLA0cYOCtNisVoGr34A7rzkzu5ePiiTD8ih4pOZ5KGDZIBzpmaxqbwZm6PbzGGZRoJkIYRpjre4Zx3yh1gJvaw0k+aObnZ5ysUJIUJXeWM7406Rj+x1WkkaCdERvLE3dGcax5qaVgdWiyIr0ccgeUoWPS7NugOh+UFIgmQhhGmqWztJj48iJtJ6yuPOLM0AJC9ZiFCnteZYUwfj0uOGPDY6wspZkzJ5Y28dLrmKFBKqWjvJSowe8iqB19zCFJJjI0M25UKCZCGEaapaHOQNMYsMkJEQzYz8JNZJXrIQIa2pvYuOrl6K0oYOkgHOm5ZFvd3JDrmKFBJqWh0+p1oARFgtnD05k3f314fkByEJkoUQpqlu7fT5BXVZaSZbjjVjD9HcNSEEVLf6Xv0AYPnkLKwWJVUuTmFvtY2a1uAokVnd6vD53HqdMyWLxvYutle2mDMoE0mQLIQwja8zyeAuBdfj0nx0qNHkUQkhzFLTOryFXSlxUSwsTpW85EH85vUDrPzdOpb96m3WHQxsOprWelgTH15nTcrEokKzJrYEyUIIU9gc3bQ5e3x+QZ03LoXYSCvvj8GV7m3OHv77hd3c+cRWyhtCt/C+ENW24QXJ4K5ysa/GTkVTh1nDCknHWzr5/VsHOW9qNsXpcXzjqe10dgWuXF5Lh7uRyFDd9vpLiYti/rhUCZKFEMKr2lsqyMeZ5OgIK4tL0sZkXvJ/PruThz8q55XdNaz5y8e0dHQFekhCjEh1SycRFkV6QrTPP3P+tGwAmU3u57H1RwH470un8ZPLZlJvd/LYhmMBG483lcbXq4N9LZ+Sxe6q4Ekb8ZUEyUIIU1S1usu/5Q1j1mFpaSZHGtrH1IzSwVo7L2yv4o7lE3n6S2dQZ3fyq1f3B3pYQoxITauD7KQYn6sfAIxLj6c0K4HXJS/5U9buqmHJxAwKUuNYND6NhcWp/P3jo2gdmAVw1Z7X9OHOJEOf7nv7Q2s2WYJkIYQpvDPJw5l1WOopBTeWUi5e2F6FRcEXzihmZkEynz2tiCc3Vpx4QxIilFS3OkYURJ03LZv1R5po7ZCFu+AOSA/Xt7OsNPPEtqsXFHKkoZ0tx5oDNCbPa/owF+4BTM5OJD8lNuRSLiRIFkKYoqqlE4uCrETfL7tOzEogJykm4AtU/Om13bUsLE47cXn6lqUlaOBvH5QHdFwitFS1dHKw1h7oYVBjG2GQPDWbXpfmnQOhFUSZ5cMy9wLmJRMzTmy7aGYusZFWntlyPCBjqm7txGpRZA7jNd1LKcXyKZl8UBZabcglSBZCmKKqtZPspBgirL6/zCilOLM0gw/KGsdEi+pam4P9tXbOnZp1YlthWhwrZuTw5MaKkHozEYGz7mA9Z//qHc7/zXv8XwBTdbzVD4aTYuU1pzCFjIRoXtlVY8LIQs/2yhbio6xMyUk8sS0hOoJzpmTx2u7agNQcrm51kD2MRiL9nTMli46uXtYfaTJ4ZOaRIFkIYYrqluEVnfdaWppBa2c3O8dAc4Gtx1oAWFCc9qntqxcW0trZzZt7ZVZtIG/vr+PcX7/DzQ9voql9bC9ydLk0//WvXRSkxfKZ2Xn84e0y1h8OTBnF1k5v9YPhX463WhQXz8zhrX11Uisd2F1lY1peEpZ+AekF07NpaHOytaLF72OqbnH4vBB7IGdMyCAm0sJbIbRAU4JkIYQpqls7R/SC6r28+P4YSLnYWtFMpFUxLTfpU9vPmJBBbnIM/9xcEaCRBa96u5M7/rEFR7eL9w7Wc+eT2wK2kCkYrD/SRHljB/9xTin/e+UscpNj+MUr+wIyluph1kju79I5eTh7XGN+AV+vS7O32sb0vOST9p09OYsIiwrIY1Td2jmiVBqvmEgrS0szeTVAM+EjIUGyEMJwWmuqWh3kjyBIzkiIZnpeEu+NgVJw2ytamJabREyk9VPbrRbFFfPyefdAPQ1tzgCNLjg9+vFROrp7eeSmRXx3xRTeO1AfcivmjfTC9ioSoiO4cHoOsVFWvnz2BLYea2FrABZ3ect7jTSQmleUSn5KLC9srzJyWCHnaGM7HV29J314BkiOjeS0kjRe2+PftBR3Ko1jRKk0fV08M5cam4OtFYFZfDhcEiQLIQzX2N5FV49rxDNKS0sz2XqsmTZnj8EjCy4HatuYknPyGyHAZ2bn4dLw6m7J0exr7c5qFo9PZ0JmAp9bPI7CtFjue+dwoIcVMOsPN3La+DRio9wftK6YV0BidAQPfVju97F4yz6O9HmvlOKS2bm8f7BhTKfRHK53NxSamJ0w4P7zp2ZzuL6dQ/VtfhtTc0c3zp6RpdL0dc7ULKKsFl7aERqva0MGyUqpQqXU20qpvUqp3Uqprw1wzNlKqVal1DbP1w/67FuhlNqvlCpTSn3X6F9ACBF8TjQSGeEL6tLSDLp7dcByK/2hqb2LpvYuJmYN/EY4OTuRkox41u4MjTcTfyhvaOdgXRsXTHc3n4iKsHD94mI2lDexr8YW4NH5X53dweGGdk4r+SSnPSE6gsvm5vPKrhq/5/bWtDqwKMgcRiOR/i6dnUePS/PyzmoDRxZayhvdQfL49PgB95871f33/5Yf1yxUj6Du/UCSYiJZNimDtbuqQyLlwpeZ5B7gLq31VGAxcLtSatoAx63TWs/xfP0IQCllBe4FVgLTgDWD/KwQIoycaCSSMrIX1PnjUomJtIR1972yOvcs0GBBslKKlTNz+Ohw45ieVevrI8+HprMnf1IN5OoFBURHWHh8feA6kQXKlqPuS9b9F35eNjcfZ4/L75UiqlsdZCUOr6JNf9Nyk5iQGT+mUy4ON7STEhdJanzUgPsL0+KYnJ3Im/v8l5fsnfgYTU6y10Uzc6ludQRk8eFwDfmXrLWu1lpv8XxvB/YC+T7e/iKgTGt9WGvdBTwBrBrpYIUQoaG6xXvZdWQzyTGRVhaNTw/reslDBckAK2fk0uvSvO7n/MNgte1YC6lxkRSnx53YlhIXxblTs3hpZzU9va4Ajs7/9lTbsShOyl2dV5RCUVocz2/zb6BZM8JGIn0ppbh0dj4by5vGbEOd8oZ2igeZRfY6d2oWG8ub/dZ8pdo28pbU/Z03LZsoq4W1IXC1YFgf95RSxcBcYP0Au09XSm1XSq1VSk33bMsH+i7PrmSQAFspdatSapNSalN9ffi+MQoxFlS3OoiKsJA+yEyIL5aVZnCovp2qlvB8oyyrayM20nrKxY3T85IoSovjZUm5AGBbRQuzC1NQ6tNlsS6ZlUdDW1dI1V81wv4aG8UZ8Sct/FRKcdmcPD481ECtJ7jxh+rWzhFfPepr1Zw8tMbvQX6wKG9oZ3zGUEGyf5uvVLd0EmFRZIwilcYrKSaSpaUZrN1VE/SVaXwOkpVSCcAzwJ1a6/7JX1uAcVrr2cDvgX95f2yAmxrwEdFa36+1XqC1XpCZmTnQIUKIEHG8pZPc5JiTanwOx5neFtVhmnJxqL6Nksz4Uz5G3pSLD8oaxny73s6uXg7U2ZldkHLSvuWTs4iLsvLijrEVVO2rsTN1kIWfq+bm49Lwbz+lLXirH+QkjX6msTgjnvnjUnlmc2XQB1FGc3T3UtXqGDJInlOYQlp8lN/aPNe0OshOihlxI5H+Vs7M5XhLZ9CnXPgUJCulInEHyP/QWj/bf7/W2qa1bvN8/zIQqZTKwD1zXNjn0AJgbL2KCTEGVbeOrJFIX5OzE8lMjOa9ME25qGjqYFyftIHBrJieQ49L89b+sV079lB9G1rD5D4dyLxio6ycNzWbtbtq6B4jKRcdXT0cbewY8PEAmJCZwMz8ZL/l9tqdPXR09Y76ee91xbx8Dta1jYmmQn1VNHUADPnaYLUolk/O4p399X5JM6oaZY3k/i6Ynk1UhIXntwamxbavfKluoYAHgb1a67sHOSbHcxxKqUWe220ENgKlSqnxSqkoYDXwglGDF0IEp+qWTvJGWSpIKcXS0gw+KGsIiVXQw6G15nhLp091pGcXpJCdJO16veWuJmQOnMN98axcWjq62TBGUi6OeYKpU804Xjo7jx2VrZQ3tJs+HiMXdoE7hSYqwsIzmysNub1QUWPzvTLQuVOzaO3sZvNR82sO1xgw8dFXUkwk50/N5t87qoP6g60vM8lLgM8D5/Qp8XaRUuo2pdRtnmOuAnYppbYD9wCrtVsPcAfwKu4Ff09prXeb8HsIIYJEr0tTa3eSa0Bu4tLSDJo7utldFV7lverbnDh7XBSkDj2TbLEoLpyew7sH6uns6vXD6ILTobo2LAqKMwZ+zJaVZhIbaR0zHybKG4aecbx4Vi7gn5SL6lHWSO4vOTaS86dl88L2Krp6gjeIMlqtzd08KDtp6NzfpaUZRFoVb5qccuFNpTEySAb31YKm9i7e3R+8Vwt9qW7xvtZaaa1n9Snx9rLW+j6t9X2eY/6gtZ6utZ6ttV6stf6wz8+/rLWepLWeoLX+qZm/jBAi8OrsDnpd2pBV0N4W1eGWcnG82R1Q+NqR8MLpOTi6Xbx7ILweh+Eoq29jXHo80RHWAffHRlk5e3Imr+6uCbsrDwM51uSeHR6XNvhMcl5KLIuK03hhe5Xpub2j7bY3kKvmFdDc0e23vNtg4F1omZ009OOYGBPJ4pJ03txrbiqWt5HISKsVDWbZpEzS46N4LohTLqTjnhDCUN5qFKNNtwDISoxhSk5i2C3eq/QEyQVpvj1Gi8ankRwbyWtjuPteWV3boKkWXitm5FBndwb9YiAjHG3sIDk2kuS4yFMe95k5eRysa2N/rd3U8VS3OlDK/Zw1ytLSDDITo3lmy9hJuai1OUiOjTypYslgzpmSxaH6dlNTaqpajL1K4BVptfCZ2Xm8vreW1s7gXJgsQbIQwlBV3m57BqRbgHu2YdPRJjq6wqdF9fGW4c0kR1otnDc1mzf21gZ1/p5Zel2a8oYOJmSeesX/8ilZRFrVmGjlfczHhZ8XzcjBalG8YHI5tZpWBxkJ0URFGBdWRFgtXDYnj7f31dHY5jTsdoNZrc3hU6qF17lT3N333jBxNtl7lSDXgKuD/V0xL5+uHlfQdliUIFkIYahPchONeUE9c6KnRXUYLciqbHbPAibGnHoWsK8Lp2djc/TwcRi36h5Mnd1BV6+LoiGCwqSYSJZMzOCVEKi/OlpHGzsoShs6SE5PiGbJxAz+vcPclItqm/E5qwBXzi+gx6X9Vsou0GptTp9SLbyK0uMozUowNSXF6HzzvmbmJzMhM57ntgRnyoUEyUIIQ1W1OIiPspIUE2HI7S0an0ZUhIV1B8In5eJ4s2+VLfpaNsm9MG0szJL2dyI9xYeFjium53CsqYO91eamFwRST6+L4y2dPs0kg7vKRUVTJ9tMTEOpae00JYiakpPE9LwkngnSIMpotTbHsFNWzp2azYYjTdgc5qQsVLc6DGsk0p9SiivmFbChvMkvVViGS4JkIYSh3F23Yk/qijZSMZFWThufxvtl4bNorbK5k4LU4QXJMZHuhWmv7a4dEwvT+qpsdldy8OUxO29aNhYFr4Txh4mGti56XdrnqzXemrRm1kyubnGQM4wZ0OG4cl4BO4+3sr8mfD/4ALhcmjq7k5zk4QWj50/LoselTVvAV21wI5H+rpxXgEXB05srhj7YzyRIFkIYqqrFYXju2pkTMzhQ2xYWLapP1EgeZpAM7ioXY2VhWl+VTb7ncGckRLOwOI1Xw7gUXJ3d9woI4E5DWT45kxd3VNNrwgcsu6Mbu7PHlJxVgEvn5BFhUTy9KfiCKCM1trs//Awn3QJgbmEq+SmxpuWdV5t0lcArJzmGe6+bx41Lxpt2HyMlQbIQwlDVrZ3kGfyCet409+KUtWEQ+LSNojOZd2HaWKtycbylk8zEaJ9X/K+YkcP+WjuHPQ1Iwo23lm5Wou8zjpfOzqfe7mT9EeNz2qu9C7tMCqQyEqI5f1o2z2ypxNkTvrXCveXfhptuYbEoPjM7j/cONpiywLG61WFoab+BrJyZa0o6x2hJkCyEMIyzp5eGti7D62lOyExgam4SL+0I/cU7nwQ4w3/TSY6N5PQJGbyyO/wXpvU13PSUC6fnAPDq7vBs5e2dSc4aRhWEc6ZkER9lNWUB3ImyjybNJAOsXlREc0c3r4XpOYVPguSRBKSr5uTR69K8bPBEgreRiJnnNphJkCyEMIy3Ne1IUgmGcsmsXLYcazlRPi1U1dmGH+D0deH0bI42dphe9zaYVDZ3+LRozysvJZbZBclhm5dca3OiFMOaeYuNsnL+tGxe3lljeAc7s2eSAZZOzCA/JZYnN4ZvysVwuu31NyUnkUnZCbywzdgFjk3tXXT1uEzLNw92EiQLIQxz/MSMkvEvqJd4Wuy+vCM462n6qs7ufSMc2WN0/rRslIJXd4XvjFpfWmuqWhzD/pu6cEYO2ytawiKPvb96u4P0+CgircN7C790Th6tnd2sM7iDZXVLJ0qN/G/aFxaL4poFhbxf1sCxxg7T7ieQamyOYX/48VJKcensPDaWN1PRZNzj4617LzPJQggxSt52ywUpvs/6+WpcejyzC1N4alNFSKcaDKft7ECyEmOYX5QatrOk/bV0dNPV6yJ7mOkpKzwpF+GYv11rc44oXefMiZkkx0YaXuWiqtVBVmL0sIP24bpmobsKwpObjpl6P4FSZ3M3ZBnp43jZ3HyUgqc3G9eh0DvxMdxqPOFCgmQhhGGOe2aUzFrkcd2iQg7WtbHpaLMpt+8PtTYn8VFWEqJHXkf6wuk57K22GTpjFKxqh1nJwaskM4FJ2Qlh+WGizu4YUbpOVISFi2bm8truWtqcxnWwdFc/MD+Iyk2O5ezJWTy9qZKeMOw8Odxue/0VpMaxrDSTpzZWGPb4HPdDvnkwkyBZ+E1Dm5Pb/7GFzz+4nl3HWwM9HGGC4y2dZCUa25q2r8/MziMxOoLH1ofuTFKt3THqy9LehWmvhEG1j6HUeRc6jiB4WDE9hw1HmsKupXGtzTnsmXWvq+YX0Nnda+gi2OoRpMOM1LULC6mzO03tMBcoNaM4r15rFhVRY3Pwzn5jUmqqWjqJjbSSGud7d9BwIkGy8JuvP7mN1/fWsrvKxucfXH9ihbYIHyPpJDcccVERXD4vn5d2VtMQooFPnc1B5jBKdw2kKD2OmfnJ/MvgRTrByJvDPZxyZ14XzsjBpeENk5osBEJPr4vGNueIF37OK0qhJDOepzcZc0lea02Vn2aSwV2lIzMxOiwX8NXZHGSP8ircuVPdj88TG42ZSDje3EleSoxhzaFCjQTJwi82H21i3cEGvrNiCk996XTanb38cu3+QA9LGKyqtZP8YVQhGIkbziimu9fFQx+Um3o/Zqm1OQ1Z4HTV/AJ2V9nYU2UzYFTBa6S1YwGm5SZRmBYbVjPuje1duDRkjfBvSCnF1fML2XS02ZA60i0d3Ti6XaZWtugr0mrh6vkFvL2/jurW8FmU2dXjorG9a9Qzyd7H5619dYZUAvLHa3owkyBZ+MXz26qIibSwZlEhE7MSuP70cTy3tfJEu1kRWD29Lv7n37u56Hfr+NfWkc1OulzaL5ddJ2QmcOG0HB75qNzQvEp/0FpTZx9d3qHXqjl5RFktQdnK1Uj1dieJMRHERvnWSKQvpRQrpufwQVkjNke3CaPzv7oRNBLp74p5+VgU/NOABV5Vrf7PWV29sAgNPB7CaVf9fdJFcfSvDdedVgTAIx+Wj/q23FcHx2b5N5AgWfiBy6VZu6uGc6ZkERflXqx045njUUrx6EdHAzw6AfDg+0f42wfltHZ2c+eT2/jwUMOwb6O+zUlXr4sCP7xZ3nb2BGyOnpB7k7Q5enB0uwyZSU6Ji+L8adk8v63K8Lq3waTO7hhVQLhiRg5dvS7eDpMc1uG2pB5IdlIMZ03K5Nktx0fdptpbG91fM8ngTjdaPjmLxzYcC5sOfCdqJBvwOBakxrFyZi6PbTg2qokER3cvje1d5PkplSYYSZAsTHegzk693ck5U7JPbMtPieXC6dk8vbmS7jBcpRxKel2av6w7wrJJmbzxjbMoTo/j/z23a9iro/25CnpOYQpnTEjngfcPh9Sb5CeNRIwJKK6aX0BTexdv7QufnNv+RpueMrcwlazEaP69PbTra3uNpCX1QK5eUEiNzTHqmsnVAZhJBnfaVUNbF2t3hkcqjfe1YbTpFl63LC3B7ujh6U0jv9LkrTFuRnOoUDFkkKyUKlRKva2U2quU2q2U+toAx3xWKbXD8/WhUmp2n33lSqmdSqltSqlNRv8CIvhtKneX61pYnPqp7VfMdb/BG13YXgzPR4caaWhzsmZhIbFRVr67cgqHG9qH3d70aGM7AOPS/ZO/dttZE6i1OUecHhIIJ2aLRhngeC0tzSAnKYZ/hNiM+nCMdibZYlFcMc+dw+oNREKZdyZ5tIs/z52aRUpc5Khr6lY0dxIVYSFzBA0wRmPpxAzGZ8TzkAEpBcHgk/rpxjyOcwpTWDAulb9+cGTEVwvGevk38G0muQe4S2s9FVgM3K6UmtbvmCPAWVrrWcCPgfv77V+utZ6jtV4w6hGLkLP5aDOZidEUpX06eFo2KZOUuEie22psYXsxPK/tqSEuysryKVkAXDAth4lZCfzpnUPDatpxpKEDi4LCNP8EyUtLM5iel8Sf3zuMa5SXjP2l1uCZ5Airhc+fPo51Bxsoqwu/NtVaa+pszlE/XtcuLKTXpfnnFuOaLARKrc05om57/UVHWLlsTj6v766lqb1rxLdztLGdwtRYLBb/Vj+wWBTXnz6ObRUtbK9o8et9m6HG5iTSqkiNizLsNm9eOp6Kps4RL1w96uls6K/X9GA05LNMa12ttd7i+d4O7AXy+x3zodbaW93/Y6DA6IGK0LWjsoU5hSknlZCJirBwyaxcXt9TE3ILsMLJxvJm5hWlEhPpXhhlsSi+cEYxe6ttbK/0vZ51eUM7eSmxREcMf4HVSCil+NJZEzhc387rIVLiazTlzAazemEhUREWHv4w/PL7bZ09OHtco368xmfEc9r4NJ7aGNrdGsHdknq0s8he151WRFeva1SX5I81dTIuPd6Q8QzXVfMLiI+y8nAYzCbX2RxkJcYY+mHj/Gk5lGTG8/u3Do5oIqG8oZ3oCAu5JrYbD3bD+iiqlCoG5gLrT3HYTcDaPv/XwGtKqc1KqVtPcdu3KqU2KaU21dfL5fdw4ejupbyxg6k5iQPuv3R2Po5uF2+GSJATbmyObvbV2FjQLxVm1Zw8YiOtPLHB98v45Y3tjM/w75vlRTNyKEyL5b53hzfrHSi1NgeJ0RHEj6LbXn/pCdFcOjuPZ7ZUhk0FBy9vaoERM+/XLiykvLGD9UeaRn1bgWRUCUGASdmJnDY+jb+vPzqiIEprzbHG9pOuEvpLYkwkV84v4MUd1dTbQ7NuuletQVVv+rJaFHcsn8i+GvuIJhLKG9spTo/3+1WCYOJzkKyUSgCeAe7UWg9YmFMptRx3kPydPpuXaK3nAStxp2osG+hntdb3a60XaK0XZGZm+vwLiOB2uL6dXpdm0iBB8oJxqeQkxYTNoppQs6OiFa1h/rhPB8mJMZFcMiuXF7ZX+TTLr7XmSIP7BdWfIqwWbl1awtZjLWwsD/5W1SNtJzyUL5xRTEdXL09uCK9ycEbOvK+ckUtiTMSwPvgFo9HmaPf3ucXjqGjq5N0RrA1pau+ivas3YEEyeOqmu1w88lF5wMZghJrW0XfiHMils/MYlx7HPW8eHPZEwpGGdoozxm6qBfgYJCulInEHyP/QWj87yDGzgAeAVVrrRu92rXWV59864Dlg0WgHLULHgVp3nuTk7IGDZItFcdHMXN47UE9rZ3jNgoWC/Z7zMzU36aR9qxcV0dHVy7+3D50z3tTehd3RQ7GfZ5IBrppfSHp8FPe/d9jv9z1cRs4C9jUjP5nTS0Kv2sdQPlnMNPrHLDbKyhVz83l5Z03Izjr2ujT1dmP/hi6cnkNGQjR/H0E5zqNN7pxVfy3WHciEzAQumJbNwx+GXt30vupMem2IsFq4fflEdlfZeHu/72UQe3pdHGvqYHxGguFjCiW+VLdQwIPAXq313YMcUwQ8C3xea32gz/Z4pVSi93vgAmCXEQMXoWF/rZ1Iqzpl8HTJ7Fy6el28sUdSLvztYK2d1LhI0uNPXiwyryiFSdkJPs28HWlwV7YYH4BZh9goK9cuLOStfbUnShYFq1qbObNFALcvn0itzcmzW0Kn2sdQjM7hvv6MYrp6XTweorPJje1OT7c942aSoyLcTZ7e2l9HRdPwmjt5jw/kTDK4K93YHD0he5Wg3dmD3dlj2mvD5XPzKUiN5Xdvlvk8m1zV4qC7VwfkNT2Y+DKTvAT4PHCOp4zbNqXURUqp25RSt3mO+QGQDvyxX6m3bOB9pdR2YAPwktb6FaN/CRG8DtTYKclIOOVK7LmFKeSnxPLiDqly4W8Hau2UZieetKgS3Avjrl1YxPbK1iFbH3tnpCcNcsXAbGsWuTtwPbkxeNMNTlRqMPBSeV9LJqYzuyCZ+949NOwa18GqzuYkPspqWA73hMwEzpqUyaMfHw3JBiyfdNszNphas6gIBcMuJXiors2vFW0GM7colcUlaTyw7khInlejy7/1F+mZTd5e0cI7+31Lqznc4G5Z7u8UumDjS3WL97XWSms9y1PGbY7W+mWt9X1a6/s8x9ystU7ts3+BZ/thrfVsz9d0rfVPzf6FRHApb2ynJPPUTzKlFJfMymXdwQZaOkZeikgMj9aag7VtTMoe/HLaFXPzibJaeGqI1e/7qu0kRkeQH6B6moVpcSwtzeTJjRVBGyC2dnbT1esyrPxbf0opvrJ8IkcbO3hpZ3jk+NfaHYY/Xl9YUky93cnaXaH3GH2ykNHYYCovJZYLpuXw+IZjdHT5nrJwoLaN4vT4E5VxAunLZ0+kxubgX9tC70qKt356jolVJK6cV0BBaiz/99p+nxZp7q8J7MRHsJCOe8I0LpemornTp0txF8/KpceleXV3eHRPCgW1Nid2Z88pXwRT46O4cEYOz26pxNE9eK7rvhobU3IHnpH2l8+eVkSNzcFbQdp+2KhOaady/tRsSrMSuPftspCpHX0q9SbMvJ9VmklJRjx//aDc0Nv1B+9MshmX5W9ZVkJrZzdPb/K9lvSBOjulp/iQ7U/LPHXT7327LOS6uBpZxWUwUREWvn7eJHZX2XjFh/fZfTV2cpJiSB0gFW8skSBZmKbO7qSrx+XTpbiZ+ckUpcXx4o7Qm90JVYfq3ZfTJmae+k1uzcJCbI6eQQvSu1yafTV2Jg9SwcRfzp2SRXZSNI8FaV6i95JqTrJ5b4QWi+KOcyZyoLYtLGaT60yYSbZYFDecUcz2iha2HAv+iih9eT9omdHdbv64VOYVpfDA+4d96tDm7OnlaGNH0Mw0KqW464JJHG3sGFagHwxqWs1Nt/C6bG4+E7MS+PVr+4c8x3urbUzNDY5zG0gSJAvTHBvGog5vysWHhxppbAvNleehprLZt25Ki0vSKUqLG3Sx08G6NuyOHuYUpg64318irBauXVDIuwfqh70AyR9O5B0anE/a32dm5TEpO4HfvHEgaFNPfKG1ptakHO4r5xeQGB3Bg+uOGH7bZqqzO0iLjyIqwpy37luXlVDR1OnTFT1vec/SIAmSAZZPzmL+uFTuefPgKa98BZtaT+59YkykqfdjtSjuOn8Sh+rbeW7r4Gkpzp5eDtW3MWWAqkdjjQTJwjTeQMXXRR2XzMqj16VZO8IWmmJ4Kps7saihZzYtFsW1CwtZf6TpxOxzX5uOupszLBgX2CAZ4NpFRUBwLuA7UanB5Nkii0XxjfMncbi+nee3he5i2DZnD53dvabMriVER/DZxeNYu6uack9lllBg1ocGr/On5TAuPY4/v3d4yCoIB04s1g2OdAtwT7Z868LJ1Ngc/P3j0OlA6W4k4p+uditm5DAjP4nfvnFg0EWOOytb6e7VzClM8cuYgpkEycI0x5o6UAqfF3NNzU2kJDNeqlz4SWVzJ7nJsaesPOJ1zQJ36+MH1p1ci3hTeTMZCVEBrZXqlZ8Sy9mTMnlyU0XQ5SXW2hwkx0b6ZZHThdNzmJ6XxO/ePBh0j4OvPin/Zk7w8MUlxURYLDzwfvDX1/aqNyH9pC+rRXHzmePZXtHCh4caT3ns9opWYiItTBgiXcvfFpeks7Q0g3vfLguZDpS1reY0GRqIUopvXjCZyuZOntw48NXBTUfdaUjBMPERaBIkC9NUNHWQlxzr86VBd8pFHuuPNFHnuTQtzFPZ3EF+qm8fYDITo7lmQQHPbD5+Im0A3AXn395fx5kTMwK6aK+v604bR73dyZt7g2sBn7tGsv/eCO+6YBLHmjr45+bQys/08v6dmTVzmpUUwxXz8nl6UyUNIZLiZfZMMsDVCwrJTormN68fOOVs8taKZmblp/j0IdvfvrNiCi2d3fzhrbJAD8UntXaHqZUt+jtrUiYLi1P5/VtldHadnJay8UgTJRnxpJuQ+x5qgu+vW4SNY00dFKYNryTYZ2blojW8HAaLjoJdZXMnBT4GyQC3Lp1Ar9b87s2DJ7ZtONJES0c3K2bkmDHEEVk+OZOcpJigW8BnVre9wSyfnMWcwhR+/+bBkOzCV38iPcW8x+yWZSV09bp4+MNy0+7DKC6Xpr7NafoHrZhIK3csn8imo828X9Yw4DHOnl52H7cxtyjF1LGM1Iz8ZK6eX8DfPjhyotFRsPLm3vvztcGdljKFOruTh/r97Xd09fDBoQbOLM3w23iCmQTJwjQVzR0Upg7vEnxpdiKTsxOlyoXJunpc1NgcFAzj/BSlx3H96eN4fMMxtnqqAjz68VESYyJYNinTrKEOW4TVwrULC1l3MLgW8NXZHKalDgzEe1m1qtXBExuCL0d7KCcaZ5gYFHpbGj/y0VHag7ylcWN7F70u7Ze/oWsWFpKXHMPdg8wmby5vpqvXxYLiNNPHMlLfvHAy0RFWfvrSnkAP5ZRaOrrp6jGvfvpgFo1P49wpWfz+rYMnFnEDvLO/Hke3K6gmPgJJgmRhiq4eF7U2p8+X8/u6ZFYum442B32L4VBW3dqJ1gxrJhng6+dPIi85li89upn/fWUfa3fVcOMZxcRFGdMRzSirFxWiIGjaD7tcmjq7+bOA/S2ZmM5p49P4/VtlQR8E9ldrcxATaSHRoG57g/nSWRNo7ezmiSBc7NnXiVq6JqdbAERHWPnquaVsPdbCvweYsHh7fx1RVgtnTEg3fSwjlZUYwx3nTOSNvXW8d8C3LnOBUOs5r/5Mt/D6n1XTAfjesztPVML5x/qjZCdFsyiIPwD5kwTJwhTefMK85BEEybPzAEm5MFNls/sDyHCD5KSYSP76hYVEWi388Z1DLJmYzleWTzRjiKOSmxzLOVOyeWJjxYA5d/7W1NFFj0v79ZIquGeTv71iCg1tTh4IuXJn7kvQZue6zytKZVFxGg+uOxzUixzr/JB+0tc1CwqZkZ/ET17cQ1ufD1gul+a1PbWcVpJmWLtws9y4pJhx6XH8+MU9QVsOsfZEgxj/5/8WpMbxX5dMY93BBr759Hbuf+8QH5Q1csvSEiKCMNc8EORREKao8daEHUHjhPEZ8UzPS+Lf26XKhVlO1EgeZjoMwOScRN7+5tms+/Zy/n7TaUHRknYgXzqrhKb2rkFXcPuT2YvQTmX+uFRWTM/h/vcOncjzDQV1doffHq/bzi6hqtUR1CXz6vz8N2S1KH68agb1bc5PpSysK2vgaGMHV80v8Ms4RiM6wsr3L5rKwbq2k3Jvg0XtiUYi/p9JBlizqIivnzeJ57dX8bOX97FkYjo3nFEckLEEIwmShSm8HYRyR9hd7Mp5BWyvbGXX8VYjhyU8qkf5whwVYaEwLS5oKloMZGFxGgvGpfKXdUcCPkP4SX5tYN4Iv71iMo4eF/f0WXQZ7OpsTr/lcC+fnMW03CR+/9bBoJ1x9EeOdn9zi1K57awJPL6hggfWHcbR3cuvX9tPVmJ0yOSsnj8tm+WTM/nN6weobg2+FD7vB+jMAHyA9vraeaW8/vWzePyWxTx846KgrFgSKPJICFPUjDIIu3J+AbGRVh75qNzAUQmvWpuTdBM7dwWLryyfwPGWzoA3FznRbS8Al1QBSjITWLOokMc3HAv61f5edXanX2vHfv18d0vjZ0/RiSyQau0OUuIiiY7w75Wbu86fxIrpOfzkpb3M/p/X2Hm8lR+tmu73cYyUUor/uXQGPS7Nj18MvkV8NTYHqXH+qZ9+KhOzEjh9QrqkWfQjj4YwRY3NQVyUlaSYkeWsJcdGcvm8fJ7fVkVze5fBoxNmNyUIFssnZ7FofBp3v34goI0FvHmHAZ0tOncSUREWfvXqvoCNwVftzh7anD1+rQZy3tQsZuYn8/u3grMBS53NaXpL84FEWC3c+9l5/O+Vs7hiXj4P3biIFTNy/T6O0ShKj+Or50zk5Z01vLM/uOqn17Q6yB3B2h3hHxIkC1PUtDrISR7dopvrTx+Hs8fFU5uCe9V5KPJHU4JgoJTiB5dMo7mji9+9EbhUgzq7g7T4qIDOvmUmRnPrshJe3lnDFk8Jv2D1Sbc9//2NumeTS6lo6uSZIGzAUuvHmfX+rBbFNQsL+fkVszgriMo9Dscty0ooyYznB8/vxtEd+MW8XtWtjhGnJQrzSZAsTFHd2jnqkjZTcpI4bXwaj3x0NChndkJZnd1/3d8CbUZ+MmsWFfG3D44ELDgMlg8ltywtISMhmp+/vPeU3dQCzZuekuPn4GH55CxmF6bw+7fK6OoJrtecej/X2Q430RFWfrJqBseaOvjj28HTia+6tdPvf+fCdxIkC1PU2pyGPPFvXVbC8ZZOXgjiVeehptelqbf7b1FUMPjeyinkJsfyzae2B6QknPtDSeAf7/joCL5x/iQ2ljfzUhCXWAxUDrdSiq+fV8rxlk4eW3/Ur/d9KoGqsx1uzpiYwao5edz37mEO1bcFejg4untp7uiWmeQgNmSQrJQqVEq9rZTaq5TarZT62gDHKKXUPUqpMqXUDqXUvD77Viil9nv2fdfoX0AEH5dLU2szphf9OVOymJydyH3vHsLlCt6Zr1DS2O7EpQO3iCwQEmMi+dVVszjc0M7P1+71+/1XtRjzfDDCtQsLmZabxM9e2hsUNaQH8kmQ7P/H7KxJmZwxIZ3fvXmQ1s7A5bH31djurrMtM46j9/2LpxIbZeUbT24L+BXKT6pASU5ysPJlJrkHuEtrPRVYDNyulJrW75iVQKnn61bgTwBKKStwr2f/NGDNAD8rwkxDu5Melzbk07FSii+fPYGDdW28sbfWgNGJuhOLyMbWG+4ZEzP44pLxPPLRUd7a57+/JUd3Lw1tI+s+aQarRfHfl06nqtXBn949FOjhDKim1UlclJWEADSrUErx/Yun0tLZzb1Bcln+kzrbY+s5a4asxBh+dvlMtle2BrwkYvUoS6UK8w0ZJGutq7XWWzzf24G9QH6/w1YBj2i3j4EUpVQusAgo01of1lp3AU94jhWA1jrkWsX6YrTl3/q7ZFYuhWmx/PGdQ0GdRxkqvO1tx9JMste3V0xmSk4i33p6h98aa3jfCPNSgiNIBlg0Po1LZ+dx37uHqGjqCPRwTlLrSU8JVB3u6XnJXDmvgIc+KOdYY+AfH+9rqswkG+PiWblcNb+Ae98u48OyhoCNo8bmrtss5zV4DSsnWSlVDMwF1vfblQ/0LUFQ6dk22PaBbvtWpdQmpdSm+vrg7bNulDZnD6vv/5jpP3yVmx7aGLSXPUei2uBLSBFWC19aNoFtFS28eyD8/zbMVhvgxhaBFBNp5Z41c2lz9vCtf273y4eu454W4PlBFCQDfO+iKViV4qcv+T/9ZCi1rYFfWPrNCyZjtSh++UrgS+Z5O5gGS8pOOPjvS6dTkpnAl/+xJWD5ydXy4Sfo+RwkK6USgGeAO7XWtv67B/gRfYrtJ2/U+n6t9QKt9YLMzNAsMTMcd792gI3lTVy7oJC39tfxrX9uD/SQDHMinzDZuDe5axYUUpAay69fOyCzyaN0It0iYezNJANMyk7k+xdP5Z399X5pVXu8xT0TWRAk6RZeucmx3L58Aq/sruG9IPvwWRsECx1zkmP40lklvLSzmvcPBm62EdyvqRYFGQlRAR1HOEmIjuBvX1hIhEXxxYc2nnjf8qfqFgfJsZHERfk/rUj4xqcgWSkViTtA/ofW+tkBDqkECvv8vwCoOsX2Ma25vYvHNxzj8rkF/PKqWXzjvEm8uKOat/cFV5Hzkaq1ObBaFBnxxgVhUREWvnZuKTuPt/LaHslNHo1aT83ecO+2dyqfXzyOc6dk8fO1+9hX0/8zv7GOt7gDnGCcLbp5aQnjM+L5/r92Bs3VLK21uzpOEMya3nbWBMalx/Ffz+8KaG3dmlYHmYnR0g3NYIVpcTxwwwIa7E5W3/+x39tWS43k4OdLdQsFPAjs1VrfPchhLwDXe6pcLAZatdbVwEagVCk1XikVBaz2HDumvb6nls7uXm5cUgzAlzwvxL9+fX9YzJJ6a8JaLMbmE14+N5+SjHjufu0AvVLpYsTqgqRmbyAppfjlVbNIionka49vMzUAOt7cSXZSDJFBGODERFr5+RUzqWjq5DdvHAj0cABo6eimq8cVFOlAMZFWfnLZDI40tPPHdwK3yLHGoGpB4mRzi1J55KbTqPcEylUt/guUq1o6g2qtgjiZL6/aS4DPA+copbZ5vi5SSt2mlLrNc8zLwGGgDPgL8BUArXUPcAfwKu4Ff09prXcb/UuEmtf31pKXHMP0vCTAPUt6+/KJ7Dpu4+0ga5k5ErU2c1oeR1gt3Hn+JPbX2nlxx5i/IDFidWOkJfVQMhKi+fU1s9lfa+cXa83LOz3e0hF0+ch9LS5JZ82iIh5Yd5idla2BHg619uDKv11amule5PjOIcrqApO7WmsLfPpJOJs/LpVHb1pEU3sXa/7y8YmFkmbSWlPR1EFRWpzp9yVGzpfqFu9rrZXWepbWeo7n62Wt9X1a6/s8x2it9e1a6wla65la6019fv5lrfUkz76fmvnLhIKeXhcflDVwztSsT63cvnxuPgWpsdz3zuEAjs4YZs5UXjIzlyk5ifzfa/tx9gTH5eFQU2dzkj3GZ5K9zpqUyReXjOehD8tN+4B6vKUzaMq/Dea7K6eQkRDNt5/ZEfBOc59Uxwmev9H/d4m7tu5dT2+nJwC1dY1qziQGN7colUe+uIjGNnegXGdyjnJLRzd2Z0/QrVUQnxZ81//C3IHaNjq6ellYnPap7ZFWCzecXsyG8ib2VpubI2k2M1seWyzuGqYVTZ387YNyU+4jnPW6NPVtTrKCKAAJtL5l4RrajC0L1+vS1LQ6gv6SanJsJD+9fCZ7q20BT7vwLiwNppnTrMQYfnzZDLZXtPg97cLR3UtrZ3dQPR7ham5RKg9/cSF1NgfX/3WDqSVaK5rdC3plJjm4SZDsZ9sqWgCYU5hy0r6rFxQQHWHhkY+Cpx3qcDl73G02s00ser+0NJPzpmbxh7fK/FbrNlw0tXfR69LyhttHTKSV366eg83RzXf+ucPQdQE1NgfdvTokZovOn5bN6oWF3PfuIT4+3BiwcXjLnQXbB7lLZ+dx6ew87nnzoF/TUk6UCZPnrF/MH5fGnz43nwO1dr7x1DbTOr0e89QnL5QgOahJkOxn2yqaSY2LHPDTY0pcFJfNyedfW4/T2hEc7VCHy1+zQP950VQc3b3c/XpwLDYKFdK5a2BTcpL43sopvLmvjkc/Nu5D6pH6dgBKMhIMu00z/dcl0yhOj+cbT24L2GtQjc1Balwk0RHWgNz/qfx41QwyEqL52pNbafNTI6gTdbZD4INWuFg2KZPvXzyNV3fX8tcPjphyHxVN7vMqQXJwkyDZz/bX2JmWlzRoJ6nPnz6Ozu5ent5cMeD+YOft5mb2LFBJZgLXn17MExuPsaOyxdT7Cifemfdgm6ULBl84o5izJ2fy4xf3sLG8yZDbPNzgXuhVkhlvyO2ZLT46gt9eO4c6u5PvPmvsrLqvjjcHbw53clwkv7l2DuUN7XznGf88PpXNMuMYCF9cUswF07L55Sv72HXc+CsHx5o6SIuPCkjrdeE7CZL9SGvNofp2JmYOPqs0Iz+Z+eNS+fvHR027zGOmE93c/DBTeef5pWQmRPPdZ3bSHYDFNKHok5lkCZL7U0rxu2vnUpgax22Pbj4RnIzG4fp24qOsIfV4zy5M4VsXTmbtrhr+ss7/C4mPt3QGdTWQ0yek860Lp/DSjmq/NKOpaO4gwqJksa2fKaX45ZWzSIuP4j+e2EpHl7FXDiqaOigM0g+D4hMSJPtRrc1Jm7OHiVmnvvR6/enjKG/sYF0Ae8qPlHdFsD9WpifFRPKjVTPYU23jgXXmXBILN96Z5Ex5wx1Qclwkf7lhAV29Lm56aBN2x+hSDg43tDM+M37QK0fB6tZlJayckcMv1u7jw0P+ex3SWnO8uZOC1OCeNb3trBLOn5bNT1/ayyaDrjoMprK5k9yUGGkkEgCp8VH85to5HGlo579fMLZ6bVldGxOGiAVE4Mmzzo+8NTYnnGImGWDFjBwyEqJ49KNyP4zKWLV2J5FWRWqcf9qnrpiRw4XTs/ntGwcob2j3y32Gsjq7k5QgzfcMFhMyE7jvc/M5VN/G7Y9tHVXJryMNbSGTj9yXUopfXT2bkswEvvrYVr81WGhq76KzuzeoZ5LB/fj839WzKUiN5dZHN3O00bzXnsrmTgpSgvtDQzg7Y0IGXzl7Ak9tquSZzZWG3KbN0U2NzTHkhJkIPAmS/aiszg4w5BMjOsLKtQsLeXNfHRVNo7/k60+1NgdZiTGGd9s7lR+tmkFUhIVvPr1dOvENod7uJDNBZpGHsmRiBj+9fAbvHajnBy/sHlHuqaO7l8rmToozQiMfub+E6Aju+9x8nD0ubnp4k18Wqh1vCZ1FasmxkfztxkW4tObGv22kpaPLlPupbO4Iieoo4ezr503itPFp/L9/7eJArX3Ut3fIM2FWmpU46tsS5pIg2Y/K6ttIjInw6VL3daeNQwGPbThm/sAMVGdz+v1SfnZSDD9aNZ1NR5u5793AtY4NBe5uexIk++LahUV85ewJPLb+2IjSeQ7U2tEapuSE7hvhxKwE7v3sPA7U2vmPx0c3q+6LSk8lh1AJCsdnxPOX6xdQ2dzJrY9sNrzBkbOnl1qbM+jTT8JdhNXC79fMJT46gtv+vpnm9tF9IDp4IkiWmeRgJ0GyHx1t7GB8hm/5ifkpsZw3NZsnN1bg6A6dznLu9qn+D8Ium5PPJbNy+c3rB6TaxSnUt8lM8nB884LJXDwrl5+t3csru6qH9bO7q9xNgbzt50PVWZMy+dGq6by1r46fvLTX1PvyljsLpfSChcVp/OrqWWwob+IbT203dMH1J2XCQuNDQzjLSorh3uvmUtncyQ1/2zCq9QpldW1ERVikYkkIkCDZj463dA5rhuT604tpau/i5Z3De3MOpDq7MyCNKpRS/PSymWQmRnPnE9sMX4kcDrTW7pbh0pTAZxaL4tdXz2ZuYQp3PrntRDMgX+ypspEYHUFhGMwCfva0cdyy1N2++28m1Y0Fd2pBQnQESbGhVRZr1Zx8vrfSXfHiRy/uMaw0nHcdi+SuBofTStL502fnsafKxjV//pjq1pHl6u+vsVOSEY/Vj2mJYmQkSPaTkazaXjIxnZLM+JDpwBfo9qnJcZH8+prZHGlsN33GKxTZnT04e1wykzxMMZFW/nL9ArISY7jlkU0nKrgMZefxVqbmJfk1P99M3105lQumZfPjF/fwxp5aU+7jcEO7z1fbgs2ty0r44hL3B4k/v2dM6bxD9d462xIkB4tzp2bz4BcWUtHUwWX3fjDsGspaa3Yeb2VmfrJJIxRGkiDZTxraunD2uIa1alspxecXj2NbRYtf26COVN2JGsmBC8LOmJDBLUtLeGz9Md7eVxewcQSjE+dHcpKHLT0hmvuvn0+bo4c7Hts6ZF3ujq4edh1vZcG4VD+N0HxWi+K3q+cwIz+Zrz6+le3DmFX31eH69pBpvNKfUor/d/FULpmVyy/W7uPZLaOvhHCoro2cpBhpOBFkzpqUyT+/fDoRFgtX3/cRr+6u8flnK5s7aWrvYlZhinkDFIaRINlPvI0Jhlva6Mr5BcRGWnn043ITRmWs2hPd9gJ7Of+uCyYxJSeRb/1zB02jXGARTk7USJaZ5BGZkpPEL66cyYbyJn728qmvVGw91kKPS7NofJqfRucfcVERPHDDAtITorjp4Y0cazSu+o6ju5eq1s6QLJnnZbEofn3NbE4vSefb/9zBuwfqR3V7h+rbJNUiSE3JSeK5289gUk4it/19Mw/42Hhnu2fNzJyCFPMGJwwjQbKfeEsbFQxzAUZSTCSXz8vn+W1VNLQ5zRiaYbwzlYFYuNdXdISV31w7B1tnN98LUGvdYOSvluHhbNWcfG5cUszfPijn+W3HBz3ug7IGrBbF/DCaSfbKSozhoRsX0d2r+cLfNox6pb9XeWM7WsP4EJ1J9oqOsPLn6+dTmp3Il/++ecQLib0dWieE+OMRzrISY3jy1sWsnJHDT17ay4PvD52vv/5wE3FRViaHcNWbsUSCZD/xljYaSZH8m84cT1evi4f90AJ1NLwtj7P90JJ6KFNzk7jrgkm8uruWZ7YMHsyMJZ/MJAf+/ISy/7xoKguLU/nuMzvZV2M7ab/Wmld21bC4JI3EmMgAjNB8E7MSeOCGBVS2dHLLI5sMqcBzuN7dkKMkROtK95UUE8nDNy4kNS6KLz60cUTNRqpaHT51aBWBFRNp5Z7Vc1kxPYcfv7hnyDSb98saWFySTlSEhF+hQM6Snxxv7iQ5NnJEb5oTMhO4cFoOD39Y7peC/iNVa3cQZbWQEhccgcHNS0tYVJzGf7+wO+Saspih3u4kKsIScpUDgk2k1cK9180jISaC2x7djK1fKajdVTYON7SzckZugEboHwuL0/jNNXPYfKyZuwwofXbYs0htfBgEyeBOO3vkpkX0ujTX/3XDsFO/dnpmoGfIAq+gF2G1cM+auZwxIZ3vPLODD8sGbuV+rLGDIw3tnDkxw88jFCMlQbKfVDZ3jKrV6m1nT8Dm6OHx9cHbXMRdXiw6aFamWz35gQB3STe+E932guX8hLKspBj++Nl5VDZ38o0nP/239ef3DpMQHcFnZuUFcIT+cfGsXL5/0VRe2lk9ZJ72UPbV2ClIjSU+jBapTchM4IEbFlLd6uDLf99MV4/vzVi2V7YSYVFMzQ3tOttjRVSEhT99bj7jM+L50t83D9iZ71+eFK3zp2X7e3hihIYMkpVSf1VK1Smldg2y/1tKqW2er11KqV6lVJpnX7lSaqdn3yajBx9Kjrd0jqrV6pzCFE4vSeeB9w8b3tXJKO6W1MGV71qYFscPPzONDUea+IuPCyvCVZ3dKfnIBlpYnMZ/XTKNN/bW8qVHN1HT6uClHdX8e3sV158+juQguaJitpvOHM8XzijmgfePjKqG8p4qW8g3XhnI/HGp/O+Vs1h/pIkfvrDL5zUSOypbmJKbSEyk1eQRCqN4W5XHRlq58W8bP1UusrvXxdObK1hckiZNREKILzPJDwErBtuptf6V1nqO1noO8D3gXa11U59Dlnv2LxjVSENcTauD3OTR5YLevnwitTYnT2yoMGhUxnIHycGX73rV/AJWzsjh16/tH3ZNy3DinUkWxrnhjGJ+tGo67x6oZ/HP3+T2x7YwuzCFr55TGuih+Y1Siv+6ZBoXTs/mRy/uGXZnQoA2Zw+HG9qZnheeqQWXzc3nK2dP4PENFTzkw9oSZ08vW462ML8o/BZ+hrv8lFj++oWFNHd0ceNDG0+kSD760VEqmjq5ZWlJgEcohmPIIFlr/R7QNNRxHmuAx0c1ojDk6O7F5ugZ9SzrkonpnDY+jd+/VRZ0HeW01tS0OsgZ5QcBMyil+NnlM0mLj+LOJ7eFVJtvI9XZHTKTbILrTy/m9a+fxX9eNIWfXzGTJ29dTGzU2Jr9s1oUv1s9lzmFKXztiW1sLPf1LcNtT5i08D6Vb14wmfM9zViGKg23+Wgznd29LC3N9NPohJFm5Cdz72fnsa/GzsX3rON7z+7g52v3ctakTM6ZkhXo4YlhMCwnWSkVh3vG+Zk+mzXwmlJqs1Lq1iF+/lal1Cal1Kb6+tHVlgw23qoCo51lVUrx7RVTaGhz8rcPyg0YmXFsjh7au3pHlXdtptT4KP7v6tmU1bXx81HmToairh4XzR3dUtnCJMUZ8dy6bAJrFhWN2cvjMZFWHrh+AXkpsVz/4IZh1Qj2BtVzw3jm1GJR/PbaOUzKTuSOx7acaDk9kHf21xNhUSyekO7HEQojLZ+cxaM3LSI5NpLnth7nwuk53LNmrqwJCTFGLtz7DPBBv1SLJVrrecBK4Hal1LLBflhrfb/WeoHWekFmZnh9eq7zlt4yYBZv/rhUzpuaxX3vHgqqRhneHva5KcEbhC0tzeSLS8bz8EdHeWufOW11g5W3xrbMJAszpSdE8+SXFlOcEc/ND2/khe1VPv3cx4cbmZydSFp8lMkjDKz4aHczliirhZsf3jhgi/OeXhf/2nqcsydnSqe9EHfGhAxeuONM9v14JX+4bh7JsWNjnUI4MTJIXk2/VAutdZXn3zrgOWCRgfcXMuo9TRyMygf99oopdHT18r+v7DPk9oxQ3eL+HXOTg3Mm2evbKyYzNTeJO5/YNqLapaFKuu0Jf8lKjOHJLy1mblEqX3tiKw+sO3zKxWqO7l42H23mtJLw6k44mILUOO6/fj51didX//mjk8pTvryrhjq7k6vmFwZohEIIL0OCZKVUMnAW8HyfbfFKqUTv98AFwIAVMsKddybZqFm8SdmJfHFJMU9srGDLsWZDbnO0qjwzyXlBPJMM7kvCf/7cfJRS3PrIZtqDuO60kYz+GxTiVJJiInnki4tYMd3diey/nt9FT+/A5c/WHWygo6t3TOVqzh+Xxt9vPo3m9i4uu/cDXt9Ti9aaeruTX7y8l6m5SVImTIgg4EsJuMeBj4DJSqlKpdRNSqnblFK39TnscuA1rXXfqbls4H2l1HZgA/CS1voVIwcfKurtTiwK0uONC1C+dt4kspOi+cEp3nz8qbrFgdWigrK6RX9F6XH84bq5HKyz882nR98EIRR4uyGGwvkR4SEm0sq9183jtrMm8PePj3HTw5uw92u8AvDC9iqSYyNZMsYaLMwrSuWZL59BZmI0tzyyiWW/eptz/u8dmjq6+MUVM7FaJHdViEDzpbrFGq11rtY6UmtdoLV+UGt9n9b6vj7HPKS1Xt3v5w5rrWd7vqZrrX9qxi8QCupsTjISog190UuIjuAHl0xn13Ebf34v8PV/q1o7yU409nc009LSTL63ciprd9Xw87Xhv5CvptX9ISYzyOpYi/BmsSi+u9Jd9eP9sgauvu8jjrd0nth/tLGdl3dWc+W8AiKtY6+3VWl2Is/fsYRfXDGTqTlJXDgjh2e/vITZhSmBHpoQApBVAX5QZ3eYEpxcPCuXl3fl8ts3DrB8chbTAlg+qbrFQW6QVrYYzM1Lx1PZ3MFf1h0hOymGm8O4fmWofYgR4WXNoiIKUmP5yt+3cNm9H/DTy2YwtyiVb/9zB5FWxW1nhe9zbyjREVZWLypi9aKiQA9FCNHP2PvoHgB1dqdpneh+smoGKXFRfOOpbQHtxFfd2jnqZin+ppTiB5+ZfiJv8t8+rsQPRcFaw1qMHUtLM3nmK2eQGBPBrY9uZuFP32BjeRO/vHIWWUnytymECD4SJPtBvd1pWi5oanwUv7xyJvtq7Pz85cBUu9BaU93qIC/EZpLB3QTht6vnsLA4lbue2s77BxsCPSRTuDs+ht75EeFlUnYir965jD99dh7fXTmFF7+6lFVz8gM9LCGEGJAEySbrdWka2pym5oKeMyWbm84cz0MflvPSjuG3hB2txvYunD2ukJtJ9nI3QVhISWY8tzyyic1Hg6NiiFG8H2JC9fyI8BJptbByZi63nTUhoCliQggxFAmSTdbY7sSlzS+99Z0VU5hblMJ3ntnB4frBOzmZ4ZinzmdRWpxf79dIyXGRPHLTIrKTornxbxvYXdUa6CEZxtbZQ2d3r6RbCCGEEMMgQbLJPmlJbW6QHBVh4Q/XzSPCqvjKP7bQ2eW//OSKMAiSwV0e7e83n0ZCdATXP7iBQ37+sGGWapunG6KkWwghhBA+kyDZZCdaUvuhPm1+Siy/uXYO+2vtfPuZHafscmWko43uILkwxINkcHfDevTm0wD43APrqWzuGOIngl91q7tGsswkCyGEEL6TINlk9Tb/zCR7LZ+cxbcunMy/t1fxx3cO+eU+jzV1kJ0UTUyk1S/3Z7YJmQk8ctMi2pw9fO6B9dR52oqHqppWb8twCZKFEEIIX0mQbDJvgOXPJg5fPmsCl87O4/9e288be2pNv79jTR0hn2rR3/S8ZB66cSG1Nieff2BDSAfK1a0OLMq/f4NCCCFEqJMg2WT1didJMRF+nWVVSvHLK2cxIy+Zrz2xlQO1dlPv71hjB0Vp8abeRyDMH5fGAzcs4FhTB1ff99GJ3OtQU9ncQXZSzJjsaCaEEEKMlLxrmqzObm75t8HERlm5//r5xEZFcPPDm2hsc5pyP47uXmpsjrCbSfZaMjGDf9xyGi0d3Vz5pw/ZU2UL9JCGraKpIyzyxYUQQgh/kiDZZHUmNhIZSm5yLPdfP58am4NbHtmEo9v4iheH69sBKMkMv5lkr3lFqTz1pdOxKMWVf/qQtTv9X4t6NMIxHUYIIYQwmwTJJqu3O02vkXwq84pS+e21c9ha0cLXn9yGy2VsxYuDde5UjknZiYbebrCZnJPIC3csYWpuIl/+xxbufm2/4Y+lGRzdvdTanBIkCyGEEMMkQbKJtNbU2R1+q2wxmItm5vKfK6eydlcNv3jF2NbVB2rtWC2K8RnhO5PslZUUw+O3LuaaBQXc81YZX3hoIw0mpbEYxVvCToJkIYQQYngkSDaR3dmDo9sVFFUFbl46nutPH8f97x3m0Y/KDbvdg7VtFKfHERUxNv6UoiOs/PLKWfz08hmsP9zIyt+t48OyhkAPa1DeboiSkyyEEEIMz9iIbAKk7kSN5MDXp1VK8cPPTOe8qVn88IXdvLKrxpDbPVjXFvapFv0ppfjsaeP41+1LSIqJ4LMPrufu1/bT0+sK9NBOcqxRZpKFEEKIkZAg2UT+akntK6tFcc+aucwuTOGrj2/h9VHWUHZ093K0sZ3SMRYke03NTeKFO87kirnu9Iur7vuIgyaX2xuu8sYO4qKsZCREBXooQgghREgZMkhWSv1VKVWnlNo1yP6zlVKtSqltnq8f9Nm3Qim1XylVppT6rpEDDwXeBhSBXLjXX1xUBA9/cRHT8pL5yj828+bekQfKu4634tIwMz/ZwBGGlvjoCH59zWx+t3oO5Y3tXHzP+9z7dhndQTKrfLDOzsSsBJRSgR6KEEIIEVJ8mUl+CFgxxDHrtNZzPF8/AlBKWYF7gZXANGCNUmraaAYbarwzyZkJgU+36CspJpJHvriIqblJfOnRzTy+4diIbmdbRQsAswvHbpDstWpOPq9//SzOnZrFr17dz4rfvscbe2rROrAVMA7WtlGaNTZn+oUQQojRGDJI1lq/BzSN4LYXAWVa68Na6y7gCWDVCG4nZNXbnURFWEiKjQj0UE6SHBvJP24+jSUTM/jeszv5yYt76B1mSbPtla3kp8QGRc51MMhMjOZPn5vPX65fgAZufmQTa/7yMTsqWwIyntaObursTiZlJwTk/oUQQohQZlRO8ulKqe1KqbVKqemebflARZ9jKj3bBqSUulUptUkptam+vt6gYQWWu5FIdNBe6k6MieTBGxZww+njeOD9I3zxoY20dnb79LNaa9YfbmTeuFSTRxl6zp+Wzat3LuNHq6ZzsLaNS//wAf/x+Fa/t7U+MEZqWAshhBBmMCJI3gKM01rPBn4P/MuzfaDIcNCpSq31/VrrBVrrBZmZmQYMK/Dq7I6gKP92KhFWC/+zagY/u3wmH5Q1cNm9H1BW1zbkz+2vtVNnd7K0NMMPoww9kVYL159ezDvfOps7lk/ktT01nPvrd7nnzYPDnrEfqYO17vNYKjPJQgghxLCNOkjWWtu01m2e718GIpVSGbhnjgv7HFoAVI32/kJJnc0ZNJUthnLdaUU8dstibJ3dXH7vB7y179QL+t7Z757tlyD51BJjIvnmhZN5+5tnc+GMHO5+/QCr7/+I6tZO0+97T3UrCdER5CXHmn5fQgghRLgZdZCslMpRnnwCpdQiz202AhuBUqXUeKVUFLAaeGG09xdK6tucIZWvu2h8Gi989UyK0uO46eFN/PGdskEXnv1r63FmF6aQKwGYT3KTY/n9mrn89to57KmycfE97/OByU1ItlW0MKsgGYslONN9hBBCiGDmSwm4x4GPgMlKqUql1E1KqduUUrd5DrkK2KWU2g7cA6zWbj3AHcCrwF7gKa31bnN+jeDj7OmlpaM76NMt+stPieWft53BJbPy+N9X9nPXU9tx9vR+6phtFS3sq7Fz1bxBU8zFIC6bm88LXz2T9PgoPv/geu59uwyXCekXju5e9lXbmVOYYvhtCyGEEGPBkGUXtNZrhtj/B+APg+x7GXh5ZEMLbd7yb9lBVCPZV7FRVu5ZPYfSrATufv0AlS2d/Plz80mNj8Ll0vxy7T7S4qO4bK4EySMxITOBf92+hO89u5NfvbqfLUebufuaOSTHRRp2HzuPt9Lj0hIkCyGEECMkHfdMUhtELalHQinFf5xbyu9Wz2HbsRbO/817/P7Ng9z55DY+OtzIXRdMIjHGuKBurImPjuB3q+fwo1XTee9gPZf8YR0fljUYVlf5/YMNWJQ7hUYIIYQQwxd8BXzDRH0QdtsbiVVz8pmQmcCP/r2HX79+gEir4j/Omch1i4oCPbSQp5Ti+tOLmZGfzB3/2MJ1D6xnYlYCF0zL5typ2cwpTME6wnzidQfrmVWQQkqctKMWQgghRkKCZJOE+kxyXzPyk3nqttNp6egiKsJCXJT82RhpXlEqb33zbP619TgvbK/iz+8d5o/vHCI9PopzpmTxhSXFTM/zvathrc3BtooWvnpOqYmjFkIIIcKbRDsmqbM7sFoU6fHhM5Mns5LmiYm0snpREasXFdHa0c27B+t5c28tL++s5unNlVw8M5cfXjrNpw9dz287jkvDqjl5fhi5EEIIEZ4kSDZJnc1JZkK0lN8Sw5YcF8mls/O4dHYerZ3d/O2DI/zxnUOsO1jP9y+eyjULCgft4tjd6+KRj44yf1wqJZnSREQIIYQYKVm4Z5JauzPk85FF4CXHRnLneZN45WtLmZqbxHee2clnH1jPscaBW1w//GE5lc2d3L58gp9HKoQQQoQXCZJNUmdzhEU+sggOJZkJPH7LYn52+Ux2VrZywW/dLa6b2rtOHPPq7hr+95X9nDMli+WTswI4WiGEECL0SbqFSersTuaNSw30MEQYsVgU151WxPIpmfzw+d3c/foBfvPGASZkJtDr0hxpaGdmfjL/d/XsQdMxhBBCCOEbCZJN0NXjoqm9i6wQ67YnQkNuciz3X7+AA7V2XtpRzZ5qGxYFNy4p5poFhcREWgM9RCGEECLkSZBsgoY2b7c9SbcQ5pmUncik8xMDPQwhhBAiLElOsglqbZ5GIjKTLIQQQggRkiRINkGdXWaShRBCCCFCmQTJJqiTmWQhhBBCiJAmQbIJam1Od7e9BAmShRBCCCFCkQTJJqhq6SQnKQardNsTQgghhAhJEiSb4HhLJ3kpko8shBBCCBGqJEg2QVVrJ3kpsYEehhBCCCGEGCEJkg3W69LUtDokSBZCCCGECGFDBslKqb8qpeqUUrsG2f9ZpdQOz9eHSqnZffaVK6V2KqW2KaU2GTnwYNXQ5qS7V0uQLIQQQggRwnyZSX4IWHGK/UeAs7TWs4AfA/f3279caz1Ha71gZEMMLcdbOgHIl5xkIYQQQoiQNWRbaq31e0qp4lPs/7DPfz8GCgwYV8iqbnHXSJaZZCGEEEKI0GV0TvJNwNo+/9fAa0qpzUqpW0/1g0qpW5VSm5RSm+rr6w0elv9UeWaSJUgWQgghhAhdQ84k+0optRx3kHxmn81LtNZVSqks4HWl1D6t9XsD/bzW+n48qRoLFizQRo3L3463dJIYHUFSTGSghyKEEEIIIUbIkJlkpdQs4AFglda60btda13l+bcOeA5YZMT9BbPjLZ3kSj6yEEIIIURIG3WQrJQqAp4FPq+1PtBne7xSKtH7PXABMGCFjHByrLGDorS4QA9DCCGEEEKMwpDpFkqpx4GzgQylVCXwQyASQGt9H/ADIB34o1IKoMdTySIbeM6zLQJ4TGv9igm/Q9BwuTTlje0sLc0I9FCEEEIIIcQo+FLdYs0Q+28Gbh5g+2Fg9sk/Eb5qbA6cPS6KM+IDPRQhhBBCCDEK0nHPQOUN7QCMlyBZCCGEECKkSZBsoCON7iBZZpKFEEIIIUKbBMkGKm9oJzrCQm6SVLcQQgghhAhlEiQb6EhDO+PS47BYVKCHIoQQQgghRkGCZAPtrbYzOScp0MMQQgghhBCjJEGyQVo7uzne0snU3MRAD0UIIYQQQoySBMkG2VdtA2BqrswkCyGEEEKEOgmSDbLHEyRPkyBZCCGEECLkSZBskL3VNtLio8hKjA70UIQQQgghxChJkGyQLcdamF2QjKcNtxBCCCGECGESJBugqb2Lsro2Fo5PC/RQhBBCCCGEASRINsDG8iYAFhZLkCyEEEIIEQ4kSDbAO/vriY+yMqsgOdBDEUIIIYQQBpAgeZS01ry1r5ZlkzKJjrAGejhCCCGEEMIAEiSP0qajzdTanJw/LTvQQxFCCCGEEAaRIHmUHt9wjMToCFbMyAn0UIQQQgghhEEkSB6FiqYO/r29isvn5RMXFRHo4QghhBBCCIMMGSQrpf6qlKpTSu0aZL9SSt2jlCpTSu1QSs3rs2+FUmq/Z993jRx4oGmt+Z9/78aiFLcvnxjo4QghhBBCCAP5MpP8ELDiFPtXAqWer1uBPwEopazAvZ7904A1SqlpoxlssHC5NL98ZT9v7K3j2yumkJ0UE+ghCSGEEEIIAw2ZI6C1fk8pVXyKQ1YBj2itNfCxUipFKZULFANlWuvDAEqpJzzH7hn1qE1Q0dRBd6+LmEgrcVFW4qMjiLR++jNEc3sXHx1u5MH3j7D5aDNrFhXxxSXFgRmwEEIIIYQwjRGJtPlARZ//V3q2DbT9tMFuRCl1K+6ZaIqKigwY1vB855kdfHio8VPbYiItJERHEhdlpbWzm9bObgBykmL41VWzuGp+gbShFkIIIYQIQ0YEyQNFifoU2wektb4fuB9gwYIFgx5nlv84t5RrFhTi6O6lo6uXdmcPdmcPdkcPHV09JMdGkpscy/xxqcwtSjlpllkIIYQQQoQPI4LkSqCwz/8LgCogapDtQWlxSXqghyCEEEIIIYKEEdOhLwDXe6pcLAZatdbVwEagVCk1XikVBaz2HCuEEEIIIURQG3ImWSn1OHA2kKGUqgR+CEQCaK3vA14GLgLKgA7gRs++HqXUHcCrgBX4q9Z6twm/gxBCCCGEEIbypbrFmiH2a+D2Qfa9jDuIFkIIIYQQImTI6jMhhBBCCCH6kSBZCCGEEEKIfiRIFkIIIYQQoh8JkoUQQgghhOhHgmQhhBBCCCH6Ue7iFMFFKVUPHA3AXWcADQG4X+Ffcp7HBjnP4U/O8dgg53lsCNR5Hqe1zhxoR1AGyYGilNqktV4Q6HEIc8l5HhvkPIc/Ocdjg5znsSEYz7OkWwghhBBCCNGPBMlCCCGEEEL0I0Hyp90f6AEIv5DzPDbIeQ5/co7HBjnPY0PQnWfJSRZCCCGEEKIfmUkWQgghhBCiHwmShRBCCCGE6EeCZEAptUIptV8pVaaU+m6gxyNGRylVrpTaqZTappTa5NmWppR6XSl10PNvap/jv+c59/uVUhcGbuTiVJRSf1VK1SmldvXZNuzzqpSa7/n7KFNK3aOUUv7+XcTgBjnP/62UOu55Tm9TSl3UZ5+c5xCjlCpUSr2tlNqrlNqtlPqaZ7s8n8PIKc5z6DyftdZj+guwAoeAEiAK2A5MC/S45GtU57QcyOi37X+B73q+/y7wS8/30zznPBoY7/lbsAb6d5CvAc/rMmAesGs05xXYAJwOKGAtsDLQv5t8DXme/xv45gDHynkOwS8gF5jn+T4ROOA5l/J8DqOvU5znkHk+y0wyLALKtNaHtdZdwBPAqgCPSRhvFfCw5/uHgcv6bH9Ca+3UWh8BynD/TYggo7V+D2jqt3lY51UplQskaa0/0u5X3kf6/IwIAoOc58HIeQ5BWutqrfUWz/d2YC+Qjzyfw8opzvNggu48S5DsPmEVff5fyalPogh+GnhNKbVZKXWrZ1u21roa3E9cIMuzXc5/aBvuec33fN9/uwh+dyildnjSMbyX4eU8hzilVDEwF1iPPJ/DVr/zDCHyfJYg2T1135/UxQttS7TW84CVwO1KqWWnOFbOf3ga7LzK+Q5NfwImAHOAauDXnu1ynkOYUioBeAa4U2ttO9WhA2yT8xwiBjjPIfN8liDZ/YmksM//C4CqAI1FGEBrXeX5tw54Dnf6RK3nkg2ef+s8h8v5D23DPa+Vnu/7bxdBTGtdq7Xu1Vq7gL/wSUqUnOcQpZSKxB04/UNr/axnszyfw8xA5zmUns8SJMNGoFQpNV4pFQWsBl4I8JjECCml4pVSid7vgQuAXbjP6Q2ew24Anvd8/wKwWikVrZQaD5TiXiAgQsOwzqvnEq5dKbXYszr6+j4/I4KUN3DyuBz3cxrkPIckzzl5ENirtb67zy55PoeRwc5zKD2fI/xxJ8FMa92jlLoDeBV3pYu/aq13B3hYYuSygec81WEigMe01q8opTYCTymlbgKOAVcDaK13K6WeAvYAPcDtWuvewAxdnIpS6nHgbCBDKVUJ/BD4BcM/r18GHgJica+SXuvHX0MMYZDzfLZSag7uS6zlwJdAznMIWwJ8HtiplNrm2fafyPM53Ax2nteEyvNZ2lILIYQQQgjRj6RbCCGEEEII0Y8EyUIIIYQQQvQjQbIQQgghhBD9SJAshBBCCCFEPxIkCyGEEEII0Y8EyUIIIYQQQvQjQbIQQgghhBD9/H9sMzHgkbe44wAAAABJRU5ErkJggg==\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
--------------------------------------------------------------------------------