Closed saurabh-kataria closed 1 day ago
Does anyone have a simple script to get features of a short PPG signal?
I think I was able to get features for my low resolution low length signal. If you have some feedback, let me know.
import numpy as np
import pandas as pd
from dotmap import DotMap
import pyPPG.preproc as PP
import pyPPG.fiducials as FP
import pyPPG.biomarkers as BM
from pyPPG import PPG, Fiducials, Biomarkers
from scipy.signal import resample
def extract_pyPPG_features(signal_array, fs=40):
"""
Extracts pyPPG features from a 1D PPG signal by resampling it to 125 Hz.
Parameters:
- signal_array: numpy array, the raw PPG signal
- fs: int, original sampling frequency (default is 40 Hz)
Returns:
- features: numpy array of shape (204,), the extracted features
"""
# Ensure the signal is at least 15 seconds long
min_length_seconds = 15
required_length = int(min_length_seconds * fs)
if len(signal_array) < required_length:
# Tile the signal to reach the required length
num_repeats = int(np.ceil(required_length / len(signal_array)))
signal_array = np.tile(signal_array, num_repeats)
# Trim the signal to the required length
signal_array = signal_array[:required_length]
# Resample the signal from original fs to 125 Hz
fs_original = fs
fs_new = 125 # Desired sampling frequency for pyPPG
num_samples = int(len(signal_array) * fs_new / fs_original)
signal_array_resampled = resample(signal_array, num_samples)
fs = fs_new # Update the sampling frequency
# Create a DotMap object for the signal
signal = DotMap()
signal.v = signal_array_resampled
signal.fs = fs
signal.start_sig = 0
signal.end_sig = len(signal_array_resampled)
signal.filtering = True
signal.fL = 0.5 # Lower cutoff frequency (Hz)
signal.fH = 12 # Upper cutoff frequency (Hz)
signal.order = 4
signal.sm_wins = {'ppg': 50, 'vpg': 10, 'apg': 10, 'jpg': 10}
# Initialize the correction for fiducial points
corr_on = ['on', 'dn', 'dp', 'v', 'w', 'f']
correction = pd.DataFrame({key: [True] for key in corr_on})
signal.correction = correction
# Preprocess the signal
prep = PP.Preprocess(
fL=signal.fL,
fH=signal.fH,
order=signal.order,
sm_wins=signal.sm_wins
)
signal.ppg, signal.vpg, signal.apg, signal.jpg = prep.get_signals(s=signal)
# Create a PPG object
s = PPG(signal)
# Use the default fiducial point collection
fpex = FP.FpCollection(s=s)
# Extract fiducial points
fiducials = fpex.get_fiducials(s=s)
# Create a Fiducials object
fp = Fiducials(fp=fiducials)
# Calculate Biomarkers
bmex = BM.BmCollection(s=s, fp=fp)
bm_defs, bm_vals, bm_stats = bmex.get_biomarkers()
bm = Biomarkers(bm_defs=bm_defs, bm_vals=bm_vals, bm_stats=bm_stats)
# Extract the features
# Combine means and stds of ppg_sig, sig_ratios, ppg_derivs, derivs_ratios
categories = ['ppg_sig', 'sig_ratios', 'ppg_derivs', 'derivs_ratios']
stats = ['mean', 'std']
features = []
for stat in stats:
for category in categories:
values = bm_stats[category].loc[stat].values
features.extend(values)
features = np.array(features)
return features
I have signal x of length 8 sec with fs=40 i.e. x.shape = (320,)