Photoplethysmogram-based Real-Time Cognitive Load Assessment Using Multi-Feature Fusion Model
- macOS (Recommended)
- Python 2.7
- Pip
- Virtualenv
On Unix, Linux, BSD, macOS, and Cygwin:
git clone https://github.com/iRB-Lab/PPG.git
cd PPG
virtualenv venv
source venv/bin/activate
pip install -r requirements.txt
On Unix, Linux, BSD, macOS, and Cygwin:
./scripts/process_data.sh
./scripts/classify.sh
python segment.py
python preprocess.py
python extract.py
python split.py
python classify.py
- Location:
data/raw/
- Filename format:
<participant>-<label>.txt
109
110
109
109
...
- Location:
data/segmented/
- Filename format:
<participant>.json
{
"<label>": {
"sample_rate": <value>,
"signal": [ ... ]
},
...
}
- Location:
data/preprocessed/
- Filename format:
<participant>.json
{
"<label>": {
"sample_rate": <value>,
"single_waveforms": [
[ ... ],
...
]
},
...
}
- Location:
data/extracted/
- Filename format:
<participant>.json
{
"<label>": {
"sample_rate": <value>,
"ppg45": [
[ ... ],
...
],
"svri": [ ... ]
},
...
}
- Location:
data/splited/
- Filename format:
<participant>.json
{
"train": {
"<label>": [
{
"ppg45": [
[ ... ],
...
],
"svri": [ ... ]
},
...
],
...
},
"test": { ... }
}
Sensor | Feature | Dimension |
---|---|---|
PPG finger clip | PPG-45 (39 time-domain, 9 frequency-domain) | 45 |
Stress-induced vascular response index (sVRI) | 1 |
# | Feature | Description |
---|---|---|
1 | x |
Systolic peak |
2 | y |
Diastolic peak |
3 | z |
Dicrotic notch |
4 | tpi |
Pulse interval |
5 | y/x |
Augmentation index |
6 | (x-y)/x |
Relative augmentation index |
7 | z/x |
|
8 | (y-z)/x |
|
9 | t1 |
Systolic peak time |
10 | t2 |
Diastolic peak time |
11 | t3 |
Dicrotic notch time |
12 | ∆T |
Time between systolic and diastolic peaks |
13 | w |
Full width at half systolic peak |
14 | A2/A1 |
Inflection point area ratio |
15 | t1/x |
Systolic peak rising slope |
16 | y/(tpi-t3) |
Diastolic peak falling slope |
17 | t1/tpi |
|
18 | t2/tpi |
|
19 | t3/tpi |
|
20 | ∆T/tpi |
|
21 | ta1 |
|
22 | tb1 |
|
23 | te1 |
|
24 | tf1 |
|
25 | b2/a2 |
|
26 | e2/a2 |
|
27 | (b2+e2)/a2 |
|
28 | ta2 |
|
29 | tb2 |
|
30 | ta1/tpi |
|
31 | tb1/tpi |
|
32 | te1/tpi |
|
33 | tf1/tpi |
|
34 | ta2/tpi |
|
35 | tb2/tpi |
|
36 | (ta1+ta2)/tpi |
|
37 | (tb1+tb2)/tpi |
|
38 | (te1+t2)/tpi |
|
39 | (tf1+t3)/tpi |
|
40 | fbase |
Fundamental component frequency |
41 | |sbase| |
Fundamental component magnitude |
42 | f2 |
2nd harmonic frequency |
43 | |s2| |
2nd harmonic magnitude |
44 | f3 |
3rd harmonic frequency |
45 | |s3| |
3rd harmonic magnitude |
Excerpt from ppg/__init__.py
:
BASE_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
Excerpt from ppg/params.py
:
MINIMUM_PULSE_CYCLE = 0.5
MAXIMUM_PULSE_CYCLE = 1.2
PPG_SAMPLE_RATE = 200
PPG_FIR_FILTER_TAP_NUM = 200
PPG_FILTER_CUTOFF = [0.5, 5.0]
PPG_SYSTOLIC_PEAK_DETECTION_THRESHOLD_COEFFICIENT = 0.5
TRAINING_DATA_RATIO = 0.75
extrema = find_extrema(signal)
smoothed_ppg_signal = smooth_ppg_signal(
signal,
sample_rate=PPG_SAMPLE_RATE,
numtaps=PPG_FIR_FILTER_TAP_NUM,
cutoff=PPG_FILTER_CUTOFF
)
result = validate_ppg_single_waveform(single_waveform, sample_rate=PPG_SAMPLE_RATE)
single_waveforms = extract_ppg_single_waveform(signal, sample_rate=PPG_SAMPLE_RATE)
extract_ppg45(single_waveform, sample_rate=PPG_SAMPLE_RATE)
svri = extract_svri(single_waveform)
train_data, test_data = split_data_set(data, ratio)
train_features, train_labels, test_features, test_labels = get_feature_set(data, label_set, feature_type_set)
classifier = logistic_regression_classifier(features, labels)
classifier = support_vector_classifier(features, labels)
classifier = gaussian_naive_bayes_classifier(features, labels)
classifier = decision_tree_classifier(features, labels)
classifier = random_forest_classifier(features, labels)
classifier = adaboost_classifier(features, labels)
classifier = gradient_boosting_classifier(features, labels)
classifier = voting_classifier(estimators, features, labels)
make_dirs_for_file(pathname)
boolean = exist_file(pathname, overwrite=False, display_info=True)
text_data = load_text(pathname, display_info=True)
json_data = load_json(pathname, display_info=True)
dump_json(data, pathname, overwrite=False, display_info=True)
classifier_object = load_model(pathname, display_info=True)
dump_model(model, pathname, overwrite=False, display_info=True)
export_csv(data, fieldnames, pathname, overwrite=False, display_info=True)
datetime = parse_iso_time_string(timestamp)
set_matplotlib_backend(backend=None)
plot(args, backend=None)
semilogy(args, backend=None)
├── data/
│ ├── raw/
│ │ ├── <participant>-<session_id>-<block_id>-<task_level>.json
│ │ └── ...
│ ├── segmented/
│ │ ├── <participant>.json
│ │ └── ...
│ ├── preprocessed/
│ │ ├── <participant>.json
│ │ └── ...
│ └── extracted/
│ ├── <participant>.json
│ └── ...
├── models/
│ └── ...
├── results/
│ └── ...
├── ppg/
│ ├── __init__.py
│ ├── params.py
│ ├── signal.py
│ ├── feature.py
│ ├── learn.py
│ └── utils.py
├── scripts/
│ ├── process_data.sh
│ └── classify.sh
├── segment.py
├── preprocess.py
├── extract.py
├── split.py
├── classify.py
├── requirements.txt
├── README.md
├── LICENSE
└── .gitignore