PPG信号滤波过后的时频分析_ppg滤波算法-程序员宅基地

技术标签: python  信号处理  

 PPG信号的 时域图、频域图、时频图、小波变换图

 

 
import os
import time
import traceback
import pandas as pd
import plotly.plotly as py
import plotly.graph_objs as go
from plotly.offline import iplot, init_notebook_mode
import plotly
import plotly.offline as pltoff
import numpy as np
import pandas as pd

# setting offilne
plotly.offline.init_notebook_mode(connected=True)

def isNone(d):
    return (d is None or d == 'None' or
            d == '?' or
            d == '' or
            d == 'NULL' or
            d == 'null')

 

class Plotly2Html(object):
    """

    """

    def __init__(self, dataset):
        self.dataset = dataset

    def ppg_single_line_plots(self, name, title):
        # dataset = {'x': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        #            'y': [5, 4, 1, 3, 11, 2, 6, 7, 19, 20],
        #            'z': [12, 9, 0, 0, 3, 25, 8, 17, 22, 5]}

        data_g = []

        tr_x = go.Scatter(
            x=self.dataset['x'],
            y=self.dataset['y'],
            name='PPG_G',
            mode='lines'
        )
        data_g.append(tr_x)

        # tr_z = go.Scatter(
        #     x=self.dataset['x'],
        #     y=self.dataset['z'],
        #     name='z'
        # )
        # data_g.append(tr_z)

        layout = go.Layout(title=title, xaxis={'title': 'number of ppg singnal'}, yaxis={'title': 'ppg value'},
                           font={
                               'size': 16,
                               'family': 'sans-serif'
                           }, showlegend=True,
                           legend=dict(
                               x=0.9,
                               y=1.1
                           ))
        fig = go.Figure(data=data_g, layout=layout)
        print(name)
        pltoff.plot(fig, filename=name)

    def hr_two_line_plots(self, name, title):
        # dataset = {'x': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        #            'y': [5, 4, 1, 3, 11, 2, 6, 7, 19, 20],
        #            'z': [12, 9, 0, 0, 3, 25, 8, 17, 22, 5]}

        data_g = []
        tr_x = go.Scatter(
            x=self.dataset['x'],
            y=self.dataset['y'],
            name='Products heartRate',
            mode='lines'
        )
        data_g.append(tr_x)

        tr_z = go.Scatter(
            x=self.dataset['x'],
            y=self.dataset['z'],
            name='std heartRate',
            mode='lines'
        )
        data_g.append(tr_z)

        layout = go.Layout(title=title, xaxis={'title': 'number of samples'}, yaxis={'title': 'heartRate value'},
                           font={
                               'size': 16,
                               'family': 'sans-serif'
                           }, showlegend=True,
                           legend=dict(
                               x=0.9,
                               y=1.1
                           ))
        fig = go.Figure(data=data_g, layout=layout)
        print(name)
        pltoff.plot(fig, filename=name)

    def hr_error_value_two_line_plots(self, name, title):
        """
         方便观察不同信号质量下的心率测量的误差值
        """
        # dataset = {'x': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        #            'y': [5, 4, 1, 3, 11, 2, 6, 7, 19, 20],
        #            'z': [12, 9, 0, 0, 3, 25, 8, 17, 22, 5]}
        data_g = []
        tr_x = go.Scatter(
            x=self.dataset['x'],
            y=self.dataset['y'],
            name='Error value',
            mode='lines'
        )
        data_g.append(tr_x)

        tr_z = go.Scatter(
            x=self.dataset['x'],
            y=self.dataset['z'],
            name='PPG Signal quality',
            mode='lines'
        )
        data_g.append(tr_z)

        layout = go.Layout(title=title, xaxis={'title': 'number of samples'},
                           yaxis={'title': 'PPG Signal quality and Error value'},
                           font={
                               'size': 16,
                               'family': 'sans-serif'
                           }, showlegend=True,
                           legend=dict(
                               x=0.9,
                               y=1.1
                           ))
        fig = go.Figure(data=data_g, layout=layout)
        print(name)
        pltoff.plot(fig, filename=name)

    # 生成柱状图
    def bar_charts(name):
        dataset = {'x': ['Windows', 'Linux', 'Unix', 'MacOS'],
                   'y1': [45, 26, 37, 13],
                   'y2': [19, 27, 33, 21]}
        data_g = []
        tr_y1 = go.Bar(
            x=dataset['x'],
            y=dataset['y1'],
            name='v1'
        )
        data_g.append(tr_y1)

        tr_y2 = go.Bar(
            x=dataset['x'],
            y=dataset['y2'],
            name='v2'
        )
        data_g.append(tr_y2)
        layout = go.Layout(title="bar charts", xaxis={'title': 'x'}, yaxis={'title': 'value'})
        fig = go.Figure(data=data_g, layout=layout)
        pltoff.plot(fig, filename=name)

    # 生成饼图
    def pie_charts(name):
        dataset = {'labels': ['Windows', 'Linux', 'Unix', 'MacOS', 'Android', 'iOS'],
                   'values': [280, 25, 10, 100, 250, 270]}
        data_g = []
        tr_p = go.Pie(
            labels=dataset['labels'],
            values=dataset['values']
        )
        data_g.append(tr_p)
        layout = go.Layout(title="pie charts")
        fig = go.Figure(data=data_g, layout=layout)
        pltoff.plot(fig, filename=name)

    # 充满区域的图
    def filled_area_plots(name):
        dataset = {'x': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
                   'y1': [5, 4, 1, 3, 11, 2, 6, 7, 19, 20],
                   'y2': [12, 9, 0, 0, 3, 25, 8, 17, 22, 5],
                   'y3': [13, 22, 46, 1, 15, 4, 18, 11, 17, 20]}

        dataset['y1_stack'] = dataset['y1']
        dataset['y2_stack'] = [y1 + y2 for y1, y2 in zip(dataset['y1'], dataset['y2'])]
        dataset['y3_stack'] = [y1 + y2 + y3 for y1, y2, y3 in zip(dataset['y1'], dataset['y2'], dataset['y3'])]

        dataset['y1_text'] = ['%s(%s%%)' % (y1, y1 * 100 / y3_s) for y1, y3_s in
                              zip(dataset['y1'], dataset['y3_stack'])]
        dataset['y2_text'] = ['%s(%s%%)' % (y2, y2 * 100 / y3_s) for y2, y3_s in
                              zip(dataset['y2'], dataset['y3_stack'])]
        dataset['y3_text'] = ['%s(%s%%)' % (y3, y3 * 100 / y3_s) for y3, y3_s in
                              zip(dataset['y3'], dataset['y3_stack'])]

        data_g = []
        tr_1 = go.Scatter(
            x=dataset['x'],
            y=dataset['y1_stack'],
            text=dataset['y1_text'],
            hoverinfo='x+text',
            mode='lines',
            name='y1',
            fill='tozeroy'
        )
        data_g.append(tr_1)

        tr_2 = go.Scatter(
            x=dataset['x'],
            y=dataset['y2_stack'],
            text=dataset['y2_text'],
            hoverinfo='x+text',
            mode='lines',
            name='y2',
            fill='tonexty'
        )
        data_g.append(tr_2)

        tr_3 = go.Scatter(
            x=dataset['x'],
            y=dataset['y3_stack'],
            text=dataset['y3_text'],
            hoverinfo='x+text',
            mode='lines',
            name='y3',
            fill='tonexty'
        )
        data_g.append(tr_3)

        layout = go.Layout(title="filled area plots", xaxis={'title': 'x'}, yaxis={'title': 'value'})
        fig = go.Figure(data=data_g, layout=layout)
        print(name)
        pltoff.plot(fig, filename=name)


def data_singnal_quality_plot(data, quality_v_start, quality_v_end):
    data_sq0 = data[(data['singnal_quality'] >= quality_v_start) & (data['singnal_quality'] <= quality_v_end)]
    ppg_list = []
    list(map(lambda x: ppg_list.extend(list(map(eval, x.strip().split(' ')))), data_sq0['ppg'].tolist()))
    return ppg_list

def plot_ppg(data):
    ppg_0_list = data_singnal_quality_plot(data, 0, 100)
    dataset = {'x': [i for i in range(len(ppg_0_list))],
               'y': ppg_0_list}
    plt2html = Plotly2Html(dataset)
    plt2html.ppg_single_line_plots("ppg_html_pig.html", "HeartRate_dayLife_24h PPG singnal")


def plot_heartRate(data):
    data = data[(data['heartrate'] > 30) & (data['std_heartrate'] > 30)]
    dataset = {'x': [i for i in range(data.shape[0])],
               'y': data['heartrate'].values,
               'z': data['std_heartrate'].values}
    plt2html = Plotly2Html(dataset)
    plt2html.hr_two_line_plots("heartRate.html", "HeartRate_dayLife_24h heartRate")


def plot_hr_error(data):
    """

    """
    data = data[(data['heartrate'] > 30) & (data['std_heartrate'] > 30)]
    data['error_value'] = data['std_heartrate'] - data['heartrate']
    dataset = {'x': [i for i in range(data.shape[0])],
               'y': data['error_value'].values,
               'z': data['singnal_quality'].values}
    plt2html = Plotly2Html(dataset)
    plt2html.hr_error_value_two_line_plots("PPG_singnal_error_value.html",
                                           "HeartRate_dayLife_24h PPG Singnal Error Value")

 

 

ppg_0_list = []
list(map(lambda x: ppg_0_list.extend(list(map(eval, x.strip().split(' ')))), dfLQ_01['ppg'].tolist()))
print("finish")

小波变换

import matplotlib.pyplot as plt 
%matplotlib inline
import pywt
cA1, cD1 = pywt.dwt(ppg_0_list, 'db3') #得到近似值和细节系数 
wap = pywt.WaveletPacket(data=ppg_0_list, wavelet='db3')
dataa = wap['a'].data
print(wap['a'].data)
print(len(wap['a'].data)) 
 
 
 
plt.figure(num='ca')
plt.plot(cA1)
plt.figure(num='cd')
plt.plot(cD1)
plt.figure(num='data')
plt.plot(dataa)
plt.show()

信号滤波

PPG最高频率220HZ,最低40HZ。

1).低通滤波

这里假设采样频率为25hz,信号本身最大的频率为220hz,要滤除220hz以上频率成分,即截至频率为220hz,则wn=2*220/25=17.6。Wn=17.6

from scipy import signal
b, a = signal.butter(8, 0.8, 'lowpass')   #配置滤波器 8 表示滤波器的阶数
b, a
(array([ 0.19287327,  1.5429862 ,  5.40045169, 10.80090339, 13.50112924,
        10.80090339,  5.40045169,  1.5429862 ,  0.19287327]),
 array([ 1.        ,  4.78451489, 10.44504107, 13.45771989, 11.12933104,
         6.0252604 ,  2.0792738 ,  0.41721716,  0.0372001 ]))
filtedData = signal.filtfilt(b, a, ppg_0_list)  #data为要过滤的信号
filtedData
array([31934.44215563, 47675.25582932, 48259.35356704, ...,
       35243.55748356, 35258.72821223, 35263.07347472])
plt.plot(filtedData)
plt.show()

高通滤波

这里假设采样频率为1000hz,信号本身最大的频率为500hz,要滤除100hz以下频率成分,即截至频率为100hz,则wn=2*100/1000=0.2。Wn=0.2

b, a = signal.butter(8, 0.16, 'highpass')   #配置滤波器 8 表示滤波器的阶数
filtedData = signal.filtfilt(b, a, ppg_0_list)  #data为要过滤的信号
plt.plot(filtedData)
plt.show()

dataset = {'x': [i for i in range(len(filtedData))],
           'y': filtedData}
plt2html = Plotly2Html(dataset)
plt2html.ppg_single_line_plots("ppg_highpass_html_pig.html", " PPG singnal highpass")

 带通滤波

这里假设采样频率为1000hz,信号本身最大的频率为500hz,要滤除100hz以下,400hz以上频率成分,即截至频率为100,400hz,则wn1=2100/1000=0.2,Wn1=0.2; wn2=2400/1000=0.8,Wn2=0.8。Wn=[0.02,0.8]

b, a = signal.butter(8, [0.16,0.9], 'bandpass')   #配置滤波器 8 表示滤波器的阶数
filtedData = signal.filtfilt(b, a, ppg_0_list)  #data为要过滤的信号
plt.plot(filtedData)
plt.show()
dataset = {'x': [i for i in range(len(filtedData))],
           'y': filtedData}
plt2html = Plotly2Html(dataset)
plt2html.ppg_single_line_plots("ppg_bandpass_html_pig.html", " PPG singnal bandpass")

带阻滤波

这里假设采样频率为1000hz,信号本身最大的频率为220hz,要滤除40hz以上,400hz以下频率成分,即截至频率为100,400hz,则wn1=2100/1000=0.2,Wn1=0.2; wn2=2400/1000=0.8,Wn2=0.8。Wn=[0.02,0.8],和带通相似,但是带通是保留中间,而带阻是去除。

b, a = signal.butter(8, [0.16,0.85], 'bandstop')   #配置滤波器 8 表示滤波器的阶数
filtedData = signal.filtfilt(b, a, ppg_0_list)  #data为要过滤的信号
plt.plot(filtedData)
plt.show()
dataset = {'x': [i for i in range(len(filtedData))],
           'y': filtedData}
plt2html = Plotly2Html(dataset)
plt2html.ppg_single_line_plots("ppg_bandstop_html_pig.html", " PPG singnal bandstop")

带通滤波后频域变换图

In [17]:

b, a = signal.butter(8, [0.16,0.9], 'bandpass')   #配置滤波器 8 表示滤波器的阶数
filtedData = signal.filtfilt(b, a, ppg_0_list)  #data为要过滤的信号
import numpy as np#导入一个数据处理模块
import pylab as pl#导入一个绘图模块,matplotlib下的模块
 
fft_size = 1024 #FFT处理的取样长度 
x = filtedData
# N点FFT进行精确频谱分析的要求是N个取样点包含整数个取样对象的波形。因此N点FFT能够完美计算频谱对取样对象的要求是n*Fs/N(n*采样频率/FFT长度),
# 因此对8KHZ和512点而言,完美采样对象的周期最小要求是8000/512=15.625HZ,所以156.25的n为10,234.375的n为15。
xs = x[:fft_size]# 从波形数据中取样fft_size个点进行运算
xf = np.fft.rfft(xs)/fft_size# 利用np.fft.rfft()进行FFT计算,rfft()是为了更方便对实数信号进行变换,由公式可知/fft_size为了正确显示波形能量
# rfft函数的返回值是N/2+1个复数,分别表示从0(Hz)到sampling_rate/2(Hz)的分。
#于是可以通过下面的np.linspace计算出返回值中每个下标对应的真正的频率:
freqs = np.linspace(0, 25, fft_size/2+1)
# np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
#在指定的间隔内返回均匀间隔的数字
xfp = 20*np.log10(np.clip(np.abs(xf), 1e-20, 1e100))
#最后我们计算每个频率分量的幅值,并通过 20*np.log10()将其转换为以db单位的值。为了防止0幅值的成分造成log10无法计算,我们调用np.clip对xf的幅值进行上下限处理

#绘图显示结果 
pl.title(u"156.25Hz and 234.375Hz WaveForm And Freq")
pl.subplot(212)
pl.plot(freqs, xfp)
pl.xlabel(u"Freq(Hz)")
pl.subplots_adjust(hspace=0.4)
pl.show()

频谱平均

对于频谱特性不随时间变化的信号,例如引擎、压缩机等机器噪声,可以对其进行长时间的采样,然后分段进行FFT计算,最后对每个频率分量的幅值求其平均值可以准确地测量信号的频谱。

def average_fft(x, fft_size):
    """
    average_fft(x, fft_size)对数组x进行fft_size点FFT运算,以dB为单位返回其平均后的幅值。由于x的长度可能不是fft_size的整数倍,
    因此首先将其缩短为fft_size的整数倍,然后用reshape函数将其转换为一个二维数组tmp。tmp的第1轴的长度为fft_size:
    """
    n = len(x) // fft_size * fft_size
    tmp = x[:n].reshape(-1, fft_size)
    tmp *= signal.hann(fft_size, sym=0)
    xf = np.abs(np.fft.rfft(tmp)/fft_size)
    avgf = np.average(xf, axis=0)
    return 20*np.log10(avgf)

xf = average_fft(x, 1000)
pl.plot(xf)
pl.show() 

短时傅里叶变换的频谱图

https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.stft.html

计算短时傅里叶变换(STFT)

scipy.signal.stft(x,fs = 1.0,window ='hann',nperseg = 256,noverlap = None,nfft = None,detrend = False,return_onesided = True,boundary ='zeros',padded = True,axis = -1 )

参数: x : array_like 时间序列的测量值

fs : float,可选 x时间序列的采样频率。默认为1.0。

window : str或tuple或array_like,可选 所需的窗口使用。如果window是一个字符串或元组,则传递给它get_window以生成窗口值,默认情况下为DFT-even。有关get_window窗口和所需参数的列表,请参阅。如果window是array_like,它将直接用作窗口,其长度必须是nperseg。默认为Hann窗口。

nperseg : int,可选 每个段的长度。默认为256。

noverlap : int,可选 段之间重叠的点数。如果没有, 。默认为无。指定时,必须满足COLA约束(请参阅下面的注释)。noverlap = nperseg // 2

nfft : int,可选 如果需要零填充FFT,则使用FFT的长度。如果为 None,则FFT长度为nperseg。默认为无。

detrend : str或function或False,可选 指定如何去除每个段的趋势。如果detrend是字符串,则将其作为类型参数传递给detrend 函数。如果它是一个函数,它需要一个段并返回一个去趋势段。如果detrend为False,则不进行去除趋势。默认为False。

return_onesided : bool,可选 如果为True,则返回实际数据的单侧频谱。如果 False返回双面光谱。请注意,对于复杂数据,始终返回双面光谱。默认为 True。

boundary : str或None,可选 指定输入信号是否在两端扩展,以及如何生成新值,以使第一个窗口段在第一个输入点上居中。这具有当所采用的窗函数从零开始时能够重建第一输入点的益处。有效选项是 。对于零填充扩展,默认为“零”。即扩展到了。['even', 'odd', 'constant', 'zeros', None][1, 2, 3, 4][0, 1, 2, 3, 4, 0]nperseg=3

填充 : bool,可选 指定输入信号在末尾是否填充零以使信号精确地拟合为整数个窗口段,以便所有信号都包含在输出中。默认为True。填充发生在边界扩展之后,如果 边界不是None,则填充为True,默认情况下也是如此。

axis : int,可选 计算STFT的轴; 默认值超过最后一个轴(即axis=-1)。

返回:

f : ndarray 采样频率数组。

t : ndarray 段时间数组。

Zxx : ndarray x的 STFT 。默认情况下,Zxx的最后一个轴对应于段时间。

import scipy.signal as signal
def stft(x, **params):
    '''
    短时傅立叶变换基本思想是将信号加滑动时间窗,并对窗内信号做傅立叶变换,得到信号的时变频谱。
    因而它的时间分辨率和频率分辨率受Heisenberg测不准原理约束,一旦窗函数选定,时频分辨率便确定下来。
    这就使它对突变信号和非平稳信号的分析存在局限性,因而不是一种动态的分析方法, 不能敏感地反映信号的突变,只适用于对缓变信号的分析。
    :param x: 输入信号
    :param params: {fs:采样频率;
                    window:窗。默认为汉明窗;
                    nperseg: 每个段的长度,默认为256,
                    noverlap:重叠的点数。指定值时需要满足COLA约束。默认是窗长的一半,
                    nfft:fft长度,
                    detrend:(str、function或False)指定如何去趋势,默认为Flase,不去趋势。
                    return_onesided:默认为True,返回单边谱。
                    boundary:默认在时间序列两端添加0
                    padded:是否对时间序列进行填充0(当长度不够的时候),
                    axis:可以不必关心这个参数}
    :return: f:采样频率数组;t:段时间数组;Zxx:STFT结果
    1.fs:表示时序信号的采样频域
    2.nperseg:表示单个时间段的长度选择,类似于时间窗的概念,对应滑窗概念里的窗长。
    3.noverlap:与前一个时间窗的相重合的时间点的长度,类似于滑窗的概念,其实就是相当于是:
     Gap = nperseg - noverlap
    4.nfft:是计算离散傅里叶变换的点数。  nfft越大,频域的分辨率就越高(分辨率=fs/nfft),但离瞬时频率就越远;noverlap影响时间轴的分辨率,越接近nfft,分辨率越高,相应的冗余就越多,计算量越大,但计算机只要能承受,问题不大。
    5.boundary:扩展参数 
    Sxx:表示最终输出的频域分析的结果,每一行代表在某一频率下所有时间窗的结果,每一列对应的是某一个时间窗下的所有频率的结果。
    f:表示输出对应的的频率。对应Sxx的每一行。
    t:表示输出对应的时间段。对应Sxx的每一列。
    '''
    f, t, zxx = signal.stft(x, **params) 
    return f, t, zxx 

import matplotlib.pyplot as plt
def stft_specgram(x, picname=None, **params):    #picname是给图像的名字,为了保存图像
    f, t, zxx = stft(x, **params) 
#     cm_light = mpl.colors.ListedColormap(['#FFA0A0','#A0FFA0',  '#A0A0FF'])
    cm_light = plt.cm.get_cmap('rainbow')
#     cm_light=plt.cm.get_cmap('flag')
#     cm_light = plt.get_cmap('PiYG')
    ct = plt.pcolormesh(t, f, np.abs(zxx), cmap=cm_light,vmin=-2,vmax=2,edgecolors='face')
    plt.colorbar(ct)
    plt.title('PPG STFT Magnitude')
    plt.ylabel('Frequency [Hz]')
    plt.xlabel('Time [sec]')
    plt.tight_layout()
    if picname is not None:
        plt.savefig('..\\picture\\' + str(picname) + '.jpg')       #保存图像
    plt.show()
#     plt.clf()      #清除画布
    pl.plot(zxx)
    pl.show() 
    return t, f, zxx 
b, a = signal.butter(10, [0.1,0.9], 'bandpass')   #配置滤波器 8 表示滤波器的阶数
filtedData = signal.filtfilt(b, a, ppg_0_list)  #data为要过滤的信号
# t, f, zxx = stft_specgram(ppg_0_list,fs=400,nperseg=500,nfft=1000,noverlap=25)
t, f, zxx = stft_specgram(filtedData,fs=440,nperseg=220, noverlap=25)

 

import seaborn as sns
fig = plt.figure(figsize=[20,6])
ax = sns.heatmap(abs(zxx),cmap="gist_earth")

 

import plotly
import plotly.offline as pltoff 
import plotly.plotly as py
import plotly.graph_objs as go
# setting offilne
plotly.offline.init_notebook_mode(connected=True)
dataset = {
    'x': [i for i in range(dfLQ_01.shape[0])],
    'y': dfLQ_01['heartrate'].values,
    'z': dfLQ_01['std_heartrate'].values
}
data_g = []
'''
['Greys', 'YlGnBu', 'Greens', 'YlOrRd', 'Bluered', 'RdBu',
'Reds', 'Blues', 'Picnic', 'Rainbow', 'Portland', 'Jet',
'Hot', 'Blackbody', 'Earth', 'Electric', 'Viridis', 'Cividis']
'''
aes1 = go.Heatmap( z=np.abs(zxx),x=t,y=f,
                 type = 'heatmap', colorscale = 'Earth')
data_g.append(aes1)

tr_x = go.Scatter(
    x= dataset['x'],
    y= dataset['y'],
    name='Products heartRate', 
    mode='lines'
)
data_g.append(tr_x)

tr_z = go.Scatter(
    x= dataset['x'],
    y= dataset['z'],
    name='std heartRate', 
    mode='lines'
)
data_g.append(tr_z) 

layout = go.Layout(
    title = 'PPG-STFT-Magnitude',
    plot_bgcolor='#ffffff',#图的背景颜色
    paper_bgcolor='#ffffff',#图像的背景颜色
    autosize = True,     
    width = 1800,
    height = 800, 
    xaxis = dict( 
        title = 'Times'
    ),
    yaxis = dict(
        title = 'Frequency'
    ),
)
fig = go.Figure(data=data_g, layout=layout)  
pltoff.plot(fig, filename="PPG-STFT-Magnitude.html")

 

import plotly
import plotly.offline as pltoff 
import plotly.plotly as py
import plotly.graph_objs as go
# setting offilne
plotly.offline.init_notebook_mode(connected=True)
data_g = []   
for item in zxx: 
    data_g.append(go.Scatter(y =np.real(item),mode = 'lines'))
    
layout = go.Layout(
    title = 'PPG-STFT-Magnitude',
    autosize = False,     
    width = 1800,
    height = 800,
#     shapes = [cross(230, 530)[0], cross(230, 530)[1], cross(230, 430)[0], cross(230, 430)[1], cross(230, 330)[0], cross(230, 330)[1], cross(300, 530)[0], cross(300, 530)[1], cross(300, 430)[0], cross(300, 430)[1], cross(370, 530)[0], cross(370, 530)[1]],
    xaxis = dict( 
        title = 'Times'
    ),
    yaxis = dict(
        title = 'Frequency'
    ),
)
fig = go.Figure(data=data_g, layout=layout)  
pltoff.plot(fig, filename="PPG-STFT-Magnitude.html")
'PPG-STFT-Magnitude.html'
fig = go.Figure(data=[go.Surface(z=np.real(zxx))])
fig.update_traces(contours_z=dict(show=True, usecolormap=True,
                                  highlightcolor="limegreen", project_z=True))
fig.layout.update(title='Mt Bruno Elevation', autosize=False,
                  scene_camera_eye=dict(x=1.87, y=0.88, z=-0.64),
                  width=1200, height=900,
                  margin=dict(l=65, r=50, b=65, t=90)
)

pltoff.plot(fig, filename="PPG-3D-STFT-Magnitude.html")

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u014033218/article/details/97369088

智能推荐

攻防世界_难度8_happy_puzzle_攻防世界困难模式攻略图文-程序员宅基地

文章浏览阅读645次。这个肯定是末尾的IDAT了,因为IDAT必须要满了才会开始一下个IDAT,这个明显就是末尾的IDAT了。,对应下面的create_head()代码。,对应下面的create_tail()代码。不要考虑爆破,我已经试了一下,太多情况了。题目来源:UNCTF。_攻防世界困难模式攻略图文

达梦数据库的导出(备份)、导入_达梦数据库导入导出-程序员宅基地

文章浏览阅读2.9k次,点赞3次,收藏10次。偶尔会用到,记录、分享。1. 数据库导出1.1 切换到dmdba用户su - dmdba1.2 进入达梦数据库安装路径的bin目录,执行导库操作  导出语句:./dexp cwy_init/[email protected]:5236 file=cwy_init.dmp log=cwy_init_exp.log 注释:   cwy_init/init_123..._达梦数据库导入导出

js引入kindeditor富文本编辑器的使用_kindeditor.js-程序员宅基地

文章浏览阅读1.9k次。1. 在官网上下载KindEditor文件,可以删掉不需要要到的jsp,asp,asp.net和php文件夹。接着把文件夹放到项目文件目录下。2. 修改html文件,在页面引入js文件:<script type="text/javascript" src="./kindeditor/kindeditor-all.js"></script><script type="text/javascript" src="./kindeditor/lang/zh-CN.js"_kindeditor.js

STM32学习过程记录11——基于STM32G431CBU6硬件SPI+DMA的高效WS2812B控制方法-程序员宅基地

文章浏览阅读2.3k次,点赞6次,收藏14次。SPI的详情简介不必赘述。假设我们通过SPI发送0xAA,我们的数据线就会变为10101010,通过修改不同的内容,即可修改SPI中0和1的持续时间。比如0xF0即为前半周期为高电平,后半周期为低电平的状态。在SPI的通信模式中,CPHA配置会影响该实验,下图展示了不同采样位置的SPI时序图[1]。CPOL = 0,CPHA = 1:CLK空闲状态 = 低电平,数据在下降沿采样,并在上升沿移出CPOL = 0,CPHA = 0:CLK空闲状态 = 低电平,数据在上升沿采样,并在下降沿移出。_stm32g431cbu6

计算机网络-数据链路层_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输-程序员宅基地

文章浏览阅读1.2k次,点赞2次,收藏8次。数据链路层习题自测问题1.数据链路(即逻辑链路)与链路(即物理链路)有何区别?“电路接通了”与”数据链路接通了”的区别何在?2.数据链路层中的链路控制包括哪些功能?试讨论数据链路层做成可靠的链路层有哪些优点和缺点。3.网络适配器的作用是什么?网络适配器工作在哪一层?4.数据链路层的三个基本问题(帧定界、透明传输和差错检测)为什么都必须加以解决?5.如果在数据链路层不进行帧定界,会发生什么问题?6.PPP协议的主要特点是什么?为什么PPP不使用帧的编号?PPP适用于什么情况?为什么PPP协议不_接收方收到链路层数据后,使用crc检验后,余数为0,说明链路层的传输时可靠传输

软件测试工程师移民加拿大_无证移民,未受过软件工程师的教育(第1部分)-程序员宅基地

文章浏览阅读587次。软件测试工程师移民加拿大 无证移民,未受过软件工程师的教育(第1部分) (Undocumented Immigrant With No Education to Software Engineer(Part 1))Before I start, I want you to please bear with me on the way I write, I have very little gen...

随便推点

Thinkpad X250 secure boot failed 启动失败问题解决_安装完系统提示secureboot failure-程序员宅基地

文章浏览阅读304次。Thinkpad X250笔记本电脑,装的是FreeBSD,进入BIOS修改虚拟化配置(其后可能是误设置了安全开机),保存退出后系统无法启动,显示:secure boot failed ,把自己惊出一身冷汗,因为这台笔记本刚好还没开始做备份.....根据错误提示,到bios里面去找相关配置,在Security里面找到了Secure Boot选项,发现果然被设置为Enabled,将其修改为Disabled ,再开机,终于正常启动了。_安装完系统提示secureboot failure

C++如何做字符串分割(5种方法)_c++ 字符串分割-程序员宅基地

文章浏览阅读10w+次,点赞93次,收藏352次。1、用strtok函数进行字符串分割原型: char *strtok(char *str, const char *delim);功能:分解字符串为一组字符串。参数说明:str为要分解的字符串,delim为分隔符字符串。返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。其它:strtok函数线程不安全,可以使用strtok_r替代。示例://借助strtok实现split#include <string.h>#include <stdio.h&_c++ 字符串分割

2013第四届蓝桥杯 C/C++本科A组 真题答案解析_2013年第四届c a组蓝桥杯省赛真题解答-程序员宅基地

文章浏览阅读2.3k次。1 .高斯日记 大数学家高斯有个好习惯:无论如何都要记日记。他的日记有个与众不同的地方,他从不注明年月日,而是用一个整数代替,比如:4210后来人们知道,那个整数就是日期,它表示那一天是高斯出生后的第几天。这或许也是个好习惯,它时时刻刻提醒着主人:日子又过去一天,还有多少时光可以用于浪费呢?高斯出生于:1777年4月30日。在高斯发现的一个重要定理的日记_2013年第四届c a组蓝桥杯省赛真题解答

基于供需算法优化的核极限学习机(KELM)分类算法-程序员宅基地

文章浏览阅读851次,点赞17次,收藏22次。摘要:本文利用供需算法对核极限学习机(KELM)进行优化,并用于分类。

metasploitable2渗透测试_metasploitable2怎么进入-程序员宅基地

文章浏览阅读1.1k次。一、系统弱密码登录1、在kali上执行命令行telnet 192.168.26.1292、Login和password都输入msfadmin3、登录成功,进入系统4、测试如下:二、MySQL弱密码登录:1、在kali上执行mysql –h 192.168.26.129 –u root2、登录成功,进入MySQL系统3、测试效果:三、PostgreSQL弱密码登录1、在Kali上执行psql -h 192.168.26.129 –U post..._metasploitable2怎么进入

Python学习之路:从入门到精通的指南_python人工智能开发从入门到精通pdf-程序员宅基地

文章浏览阅读257次。本文将为初学者提供Python学习的详细指南,从Python的历史、基础语法和数据类型到面向对象编程、模块和库的使用。通过本文,您将能够掌握Python编程的核心概念,为今后的编程学习和实践打下坚实基础。_python人工智能开发从入门到精通pdf

推荐文章

热门文章

相关标签