Example analysis of a PPG/ECG waveform using the vital_sqi package
The following notebook shows an example of PPG/ECG waveform processing using the vital_sqi package. The aim of the package is to automate signal quality classification for PPG/ECG waveforms. It is achieved by computing various signal quality indices for each signal segment and using them to form a decision.
The pipeline can be briefly summarized as follows:
Load dataset under analysis
Preprocess and segment the dataset
Compute SQI for each dataset segment
Make decision for each segment
Global Imports
[1]:
import numpy as np
import warnings
import os
import pandas as pd
import matplotlib.pyplot as plt
import vital_sqi
from vital_sqi.data.signal_io import ECG_reader,PPG_reader
Start by importing the signal via the PPG_reader function
The function expects a .csv or similar data format with named columns. The column names are used to separate between data column, timestamp columns and any additional information columns. This returns a SignalSQI class that is compatible with other vital_sqi package functions, the main class members of interest are: * signals: an ndarray of shape (m, n) where m is the number of rows and n is the number of channels of the signal * sqis: an ndarray of shape (m, n) where m is the number of signal segments, n is the number of SQIs. * sampling_rate: sampling rate in hertz (Hz)
[2]:
from vital_sqi.pipeline.pipeline_highlevel import get_ppg_sqis
file_in = os.path.abspath('test_data/ppg_smartcare.csv') #FIle input location
sqi_dict = os.path.abspath('test_data/sqi_dict.json') #input dictionary -> which sqi features
segments, signal_obj = get_ppg_sqis(file_in,
signal_idx=['PLETH'],
timestamp_idx=['TIMESTAMP_MS'],
sqi_dict_filename = sqi_dict)
100%|██████████| 21/21 [00:02<00:00, 7.20it/s]
[3]:
signal_obj.sqis[0].describe()
[3]:
| perfusion | kurtosis_1 | skewness_mean_sqi | skewness_median_sqi | skewness_std_sqi | entropy | kurtosis_2 | skewness_1 | entropy_2 | signal_to_noise | ... | hfnu_sqi | total_power_sqi | vlf_sqi | triangular_index_sqi | tinn_sqi | csi_sqi | cvi_sqi | Modified_csi_sqi | start_idx | end_idx | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 21.000000 | 21.000000 | 21.000000 | 21.000000 | 21.000000 | 21.000000 | 21.000000 | 21.000000 | 21.000000 | 21.0 | ... | 21.000000 | 21.000000 | 21.000000 | 21.000000 | 0.0 | 21.000000 | 21.000000 | 21.000000 | 21.000000 | 21.000000 |
| mean | 187.404653 | -1.360325 | 0.073129 | 0.080781 | 0.120721 | 4.343845 | -0.966196 | 0.086825 | 7.777617 | -1.0 | ... | 53.024653 | 2457.690263 | 587.473086 | 5.004001 | NaN | 1.596050 | 4.751727 | 765.778807 | 30000.000000 | 33000.000000 |
| std | 20.712381 | 0.032043 | 0.058008 | 0.035630 | 0.115958 | 0.023989 | 0.395934 | 0.113371 | 0.159168 | 0.0 | ... | 23.529422 | 3642.831489 | 998.300743 | 1.670246 | NaN | 0.695445 | 0.878519 | 742.250417 | 18614.510469 | 18614.510469 |
| min | 112.313216 | -1.396156 | -0.086416 | 0.009774 | 0.019471 | 4.313126 | -1.349569 | -0.318782 | 7.103965 | -1.0 | ... | 17.870115 | 109.769282 | 8.139479 | 2.857143 | NaN | 0.822317 | 3.590477 | 59.345391 | 0.000000 | 3000.000000 |
| 25% | 183.541473 | -1.383222 | 0.058113 | 0.061718 | 0.032456 | 4.327253 | -1.277692 | 0.063396 | 7.783738 | -1.0 | ... | 35.720578 | 222.530802 | 57.790560 | 3.555556 | NaN | 1.161429 | 3.868977 | 119.530778 | 15000.000000 | 18000.000000 |
| 50% | 186.970824 | -1.367053 | 0.070987 | 0.077784 | 0.077805 | 4.334973 | -1.103788 | 0.081037 | 7.809623 | -1.0 | ... | 54.651397 | 811.417421 | 252.630297 | 4.250000 | NaN | 1.418324 | 5.074484 | 562.534403 | 30000.000000 | 33000.000000 |
| 75% | 195.615534 | -1.354891 | 0.114273 | 0.108330 | 0.202787 | 4.367132 | -0.822027 | 0.132159 | 7.826186 | -1.0 | ... | 70.309215 | 2499.129760 | 493.237543 | 6.500000 | NaN | 1.885878 | 5.541223 | 1183.176936 | 45000.000000 | 48000.000000 |
| max | 215.095923 | -1.287866 | 0.147944 | 0.146486 | 0.455517 | 4.387753 | 0.067313 | 0.269913 | 7.893871 | -1.0 | ... | 89.929842 | 11283.942003 | 4052.382611 | 8.600000 | NaN | 3.300646 | 6.005650 | 2769.520662 | 60000.000000 | 63000.000000 |
8 rows × 79 columns
Get decision
[4]:
from vital_sqi.pipeline.pipeline_highlevel import get_qualified_ppg
rule_dict_filename = os.path.abspath('test_data/rule_dict_test.json') # location dictionary contain threshold
ruleset_order = {3: 'skewness_1',
2: 'entropy',
1: 'perfusion'}
file_in = os.path.abspath('test_data/ppg_smartcare.csv') #FIle input location
sqi_dict = os.path.abspath('test_data/sqi_dict.json') #input dictionary -> which sqi features
signal_obj = get_qualified_ppg(file_in,
signal_idx=['PLETH'],
timestamp_idx=['TIMESTAMP_MS'],
sqi_dict_filename = sqi_dict,
rule_dict_filename = rule_dict_filename,
ruleset_order=ruleset_order,
output_dir=None)
100%|██████████| 21/21 [00:02<00:00, 9.76it/s]
0it [00:00, ?it/s]
100%|██████████| 21/21 [00:00<00:00, 57.97it/s]