一、原始信号的FFT分析
模仿一个脉搏波(PPG)信号的波形
from signal_process.singular_spectrum_analysis import SSA
import matplotlib.pyplot as plt
import numpy as np
# 模拟一个信号并画出图
def plot_freq_pulse(length, freq1, freq2, freq3, freq4):
x = np.linspace(0, 15, length) # 采样频率freq=length/15
a = 4 * np.sin(2 * np.pi * freq1 * x) # 频率为freq1,幅度为2,感兴趣信号
b = 0.5 * np.sin(2 * np.pi * freq2 * x)
c = 2 * np.sin(2 * np.pi * freq3 * x)
d = 0.2 * np.sin(2 * np.pi * freq4 * x)
noise = 0.2 * (np.random.rand(length) - 0.5) # -0.1~0.1内随机噪声
f = a + b + c + d + noise
plt.subplot(211)
plt.plot(x, f)
q = np.fft.fft(f)
freq = np.fft.fftfreq(q.size, 15/length)
plt.subplot(212)
q = abs(q)
plt.plot(freq[freq>0], q[freq>0])
plt.figure()
plt.plot(x, a, x, b, x, c, x, d, x, noise)
plt.legend(['a', 'b', 'c', 'd', 'noise'])
return f
signal = plot_freq_pulse(600, 1.1, 2.0, 2.5, 4.0)
看看这个信号长啥样
看看,是不是很像PPG信号!对于这样的信号,我们一般采用的都是频谱分析,从而尽量还原原始信号。接下来不妨结合频域图看看:
频谱图可以看出信号主要由四个周期信号组成,对应了我们设计的信号。
从频谱转到单个频率下,单个的波形长这样
一般情况下,频谱分析到这里就为止了,因为一般我们的心率都在60到100次/分,在幅频图中,提取1~1.67Hz内的最大频率再乘以60就可以得到心率了。
二、SSA分析
但是在心率提取的时候,会有频谱分析时特殊情况导致提取不到最想要的频率,或者是对波形特征的准确性有了要求。那么频谱变换的使用就会受到一定程度的影响,这个时候可以采用SSA,既保留原始信号特征,又可以去噪等,端的是十分友好。
def ssa_(tseries):
dfsa = SSA(tseries, 5) # 序列增维到5个窗口
dfsa.components_to_df().plot()
dfsa.orig_TS.plot(alpha=0.4)
plt.xlabel("$t$")
plt.ylabel(r"$\tilde{F}_i(t)$")
plt.title(r"$L=2$ for the Toy Time Series")
plt.show()
dfsa.plot_wcorr()
plt.title("W-Correlation for Toy Time Series, $L=20$")
plt.show()
signal = plot_freq_pulse(600, 1.1, 2.0, 2.5, 4.0)
ssa_(signal)
看看SSA分解后的图。序列0保留了原始信号的特征而且形状大致相同,在一些较为尖锐的地方都有做平滑,这样对于特征点的识别或峰值选取无疑是有很大帮助的。
按贡献度(重要成分)做了一个相关矩阵,图片显示如下,第0个序列最重要,依次类推
三、两者联系和区别
希望来个搞数学的证明证明,俺是不行了。。。