如何使用solve_ivp或类似方法获得PPG信号的二阶导数?

时间:2019-02-19 12:07:05

标签: python scipy

我想使用solve_ivp从原始PPG信号中获取二阶导数,如何将信号值输入到函数中?

我有一个原始信号的数据集(熊猫),信号振幅为“ y”值。 “ x”值或时间值是根据采样率(即1000Hz)计算得出的,它可以将“ x”值作为样本或转换为时间单位。我认为我需要使用resolve_ivp函数,但是可能有不同的方法。我已经尝试过np.gradient,但是结果与预期不符。在尝试获得二阶导数之前,我使用0.25-3Hz的Butterworth滤波器带通来获得干净的初始信号,并在一阶导数之后再次进行滤波。

以下是原始信号的链接:https://www.dropbox.com/s/4mhz3tphdzcp4e2/2_1.txt?dl=0

import neurokit as nk
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from scipy.signal import butter, lfilter, lfilter_zi
import scipy as sc
from scipy import signal


plt.rcParams['figure.figsize'] = [20, 5]

def butter_bandpass(lowcut, highcut, fs, order=5):
    nyq = 0.5 * fs
    low = lowcut / nyq
    high = highcut / nyq
    b, a = butter(order, [low, high], btype='bandpass')
    return b, a

def butter_bandpass_filter_zi(data, lowcut, highcut, fs, order=5):
    b, a = butter_bandpass(lowcut, highcut, fs, order=order)
    zi = lfilter_zi(b, a)
    y,zo = lfilter(b, a, data, zi=zi*data[0])
    return y

filename = "0_subject/2_1.txt"

data = pd.read_csv(filename, header=None, sep="\t")
data = data.transpose()
data.plot()
plt.show()

fs = 1000.0
lowcut = 0.15
highcut = 3.0
f0 = 600

T = (len(data)-1)
nsamples = len(data)
# t = np.linspace(0, T, nsamples, endpoint=False)
t = np.linspace(0, T, nsamples, endpoint=False) / fs

y = np.array(data)[:, 0]
plt.figure(2)
plt.clf()
plt.plot(t, y, label='Noisy signal')

x = butter_bandpass_filter_zi(y, lowcut, highcut, fs, order=1)
# print(x)
plt.figure(3)
plt.plot(t, x, label='Filtered signal (%g Hz)' % f0)
plt.xlabel('time (seconds)')
# plt.hlines([-a, a], 0, T, linestyles = '--')
plt.grid(True)
plt.axis('tight')
plt.legend(loc='upper left')

plt.show()

first_derivative = np.gradient(x)
first_derivative_filter = butter_bandpass_filter_zi(first_derivative, lowcut, highcut, fs, order=1)
plt.figure(4)
plt.plot(t, first_derivative_filter)
plt.show()

second_derivative = np.gradient(first_derivative_filter)
second_derivative_filter = butter_bandpass_filter_zi(first_derivative_filter, lowcut, highcut, fs, order=1)
plt.figure(5)
plt.plot(t, second_derivative_filter)
plt.show()

这是我用solve_ivp尝试过的方法,它也给出了错误的结果:

def second_der_func(t, y): return y
sol = solve_ivp(second_der_func, [t[0], len(t)-1], [x[0]])
print(sol.y[0])

plt.plot(sol.t, sol.y[0])
plt.show()

我应该得到图像上的二阶导数曲线:

initial PPG signal and 2nd derivative curves

0 个答案:

没有答案