Skip to content

Commit

Permalink
Merge pull request #920 from neuropsychology/ecg_peak_manikandan
Browse files Browse the repository at this point in the history
[Feature] Add ECG peak detection by Manikandan (2012)
  • Loading branch information
DominiqueMakowski authored Oct 25, 2023
2 parents d7120b4 + b4a57f2 commit 323929f
Show file tree
Hide file tree
Showing 4 changed files with 313 additions and 193 deletions.
24 changes: 6 additions & 18 deletions neurokit2/data/read_xdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,11 @@ def read_xdf(filename, upsample=2, fillmissing=None):
# Rename GYRO channels and add ACCelerometer
if stream["info"]["type"][0] == "GYRO":
dat = dat.rename(columns={"X": "GYRO_X", "Y": "GYRO_Y", "Z": "GYRO_Z"})
dat["ACC"] = np.sqrt(
dat["GYRO_X"] ** 2 + dat["GYRO_Y"] ** 2 + dat["GYRO_Z"] ** 2
)
dat["ACC"] = np.sqrt(dat["GYRO_X"] ** 2 + dat["GYRO_Y"] ** 2 + dat["GYRO_Z"] ** 2)

# Muse - PPG data has three channels: ambient, infrared, red
if stream["info"]["type"][0] == "PPG":
dat = dat.rename(columns={"PPG1": "LUX", "PPG2": "PPG", "PPG3": "RED"})
dat = dat.rename(columns={"PPG1": "LUX", "PPG2": "PPG", "PPG3": "RED", "IR": "PPG"})
# Zeros suggest interruptions, better to replace with NaNs (I think?)
dat["PPG"] = dat["PPG"].replace(0, value=np.nan)
dat["LUX"] = dat["LUX"].replace(0, value=np.nan)
Expand All @@ -101,12 +99,8 @@ def read_xdf(filename, upsample=2, fillmissing=None):

# Store metadata
info = {
"sampling_rates_original": [
float(s["info"]["nominal_srate"][0]) for s in streams
],
"sampling_rates_effective": [
float(s["info"]["effective_srate"]) for s in streams
],
"sampling_rates_original": [float(s["info"]["nominal_srate"][0]) for s in streams],
"sampling_rates_effective": [float(s["info"]["effective_srate"]) for s in streams],
"datetime": header["info"]["datetime"][0],
"data": dfs,
}
Expand All @@ -127,14 +121,8 @@ def read_xdf(filename, upsample=2, fillmissing=None):
fillmissing = int(info["sampling_rate"] * fillmissing)

# Create new index with evenly spaced timestamps
idx = pd.date_range(
df.index.min(), df.index.max(), freq=str(1000 / info["sampling_rate"]) + "ms"
)
idx = pd.date_range(df.index.min(), df.index.max(), freq=str(1000 / info["sampling_rate"]) + "ms")
# https://stackoverflow.com/questions/47148446/pandas-resample-interpolate-is-producing-nans
df = (
df.reindex(df.index.union(idx))
.interpolate(method="index", limit=fillmissing)
.reindex(idx)
)
df = df.reindex(df.index.union(idx)).interpolate(method="index", limit=fillmissing).reindex(idx)

return df, info
32 changes: 16 additions & 16 deletions neurokit2/ecg/ecg_clean.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,23 +233,19 @@ def _ecg_clean_pantompkins(ecg_signal, sampling_rate=1000):


# =============================================================================
# Elgendi et al. (2010)
# Hamilton (2002)
# =============================================================================
def _ecg_clean_elgendi(ecg_signal, sampling_rate=1000):
"""From https://github.com/berndporr/py-ecg-detectors/
- Elgendi, Mohamed & Jonkman, Mirjam & De Boer, Friso. (2010). Frequency Bands Effects on QRS
Detection. The 3rd International Conference on Bio-inspired Systems and Signal Processing
(BIOSIGNALS2010). 428-431.
def _ecg_clean_hamilton(ecg_signal, sampling_rate=1000):
"""Adapted from https://github.com/PIA-
Group/BioSPPy/blob/e65da30f6379852ecb98f8e2e0c9b4b5175416c3/biosppy/signals/ecg.py#L69.
"""

order = 2
order = 1
clean = signal_filter(
signal=ecg_signal,
sampling_rate=sampling_rate,
lowcut=8,
highcut=20,
highcut=16,
method="butterworth_zi",
order=order,
)
Expand All @@ -258,19 +254,23 @@ def _ecg_clean_elgendi(ecg_signal, sampling_rate=1000):


# =============================================================================
# Hamilton (2002)
# Elgendi et al. (2010)
# =============================================================================
def _ecg_clean_hamilton(ecg_signal, sampling_rate=1000):
"""Adapted from https://github.com/PIA-
Group/BioSPPy/blob/e65da30f6379852ecb98f8e2e0c9b4b5175416c3/biosppy/signals/ecg.py#L69.
def _ecg_clean_elgendi(ecg_signal, sampling_rate=1000):
"""From https://github.com/berndporr/py-ecg-detectors/
- Elgendi, Mohamed & Jonkman, Mirjam & De Boer, Friso. (2010). Frequency Bands Effects on QRS
Detection. The 3rd International Conference on Bio-inspired Systems and Signal Processing
(BIOSIGNALS2010). 428-431.
"""

order = 1
order = 2
clean = signal_filter(
signal=ecg_signal,
sampling_rate=sampling_rate,
lowcut=8,
highcut=16,
highcut=20,
method="butterworth_zi",
order=order,
)
Expand Down
Loading

0 comments on commit 323929f

Please sign in to comment.