Rose今天主要介绍一下EMD算法原理与Python实现。关于EMD算法之前介绍过《EMD算法之Hilbert-Huang Transform原理详解和案例分析》,

SSVEP信号中含有自发脑电和大量外界干扰信号,属于典型的非线性非平稳信号。传统的滤波方法通常不满足对非线性非平稳分析的条件,1998年黄鄂提出希尔伯特黄变换(HHT)方法,其中包含经验模式分解(EMD)和希尔伯特变换(HT)两部分。EMD可以将原始信号分解成为一系列固有模态函数(IMF) [1],IMF分量是具有时变频率的震荡函数,能够反映出非平稳信号的局部特征,用它对非线性非平稳的SSVEP信号进行分解比较合适。

网友Aeo[2]提供了下面的算法过程分析。

算法过程分析

  • 筛选(Sifting)

  1. 求极值点 通过Find Peaks算法获取信号序列的全部极大值极小值

  2. 拟合包络曲线 通过信号序列的极大值极小值组,经过三次样条插值法获得两条光滑的波峰/波谷拟合曲线,即信号的上包络线下包络线

  3. 均值包络线 将两条极值曲线平均获得平均包络线

  4. 中间信号 原始信号减均值包络线,得到中间信号

  5. 判断本征模函数(IMF) IMF需要符合两个条件:1)在整个数据段内,极值点的个数和过零点的个数必须相等或相差最多不能超过一个。2)在任意时刻,由局部极大值点形成的上包络线和由局部极小值点形成的下包络线的平均值为零,即上、下包络线相对于时间轴局部对称。

  • IMF 1 获得的第一个满足IMF条件的中间信号即为原始信号的第一个本征模函数分量IMF 1(由原数据减去包络平均后的新数据,若还存在负的局部极大值和正的局部极小值,说明这还不是一个本征模函数,需要继续进行“筛选”。)

  • 使用上述方法得到第一个IMF后,用原始信号减IMF1,作为新的原始信号,再通过上述的筛选分析,可以得到IMF2,以此类推,完成EMD分解。

下面是EMD算法思路.

下面利用公式来说明上面的分析过程。

EMD算法步骤

任何复杂的信号均可视为多个不同的固有模态函数叠加之和,任何模态函数可以是线性的或非线性的,并且任意两个模态之间都是相互独立的。在这个假设 基础上,复杂信号的EMD分解步骤如下:
步骤1:
寻找信号 全部极值点,通过三次样条曲线将局部极大值点连成上包络线,将局部极小值点连成下包络线。上、下包络线包含所有的数据点。

步骤2:
由上包络和下包络线的平均值 ,得出

若满足IMF的条件,则可认为是的第一个IMF分量。

步骤3:
若不符合IMF条件,则将作为原始数据,重复步骤1、步骤2,得到上、下包络的均值,通过计算是否适合IMF分量的必备条件,若不满足,重复如上两步次,直到满足前提下得到。第1个IMF表示如下:

步骤4:
将从信号中分离得到:

将作为原始信号重复上述三个步骤,循环次,得到第二个IMF分量直到第个IMF分量 ,则会得出:

步骤5:
当变成单调函数后,剩余的成为残余分量。所有IMF分量和残余分量之和为原始信号:

用EMD进行滤波的基本思想是将原信号进行EMD分解后,只选取与特征信号相关的部分对信号进行重构。如下图中a部分为原始信号,b部分为将原始信号进行EMD分解获得的6个IMF分量和1个残余分量,c部分为将分解获得的6个IMF分量和1个残余分量进行重构后的信号,可以看出SSVEP信号用EMD分解后,基本上包含了原有信号的全部信息。

图片来源于[1]

案例1---Python实现EMD案例

结合上面的算法分析过程,从代码角度来看看这个算法。

1.求极大值点和极小值点

from scipy.signal import argrelextrema"""
通过Scipy的argrelextrema函数获取信号序列的极值点
"""
# 构建100个随机数
data = np.random.random(100)
# 获取极大值
max_peaks = argrelextrema(data, np.greater)
#获取极小值
min_peaks = argrelextrema(data, np.less)# 绘制极值点图像
plt.figure(figsize = (18,6))
plt.plot(data)
plt.scatter(max_peaks, data[max_peaks], c='r', label='Max Peaks')
plt.scatter(min_peaks, data[min_peaks], c='b', label='Max Peaks')
plt.legend()
plt.xlabel('time (s)')
plt.ylabel('Amplitude')
plt.title("Find Peaks")

2. 拟合包络函数

这一步是EMD的核心步骤,也是分解出本征模函数IMFs的前提。

from scipy.signal import argrelextrema#进行样条差值
import scipy.interpolate as spidata = np.random.random(100)-0.5
index = list(range(len(data)))# 获取极值点
max_peaks = list(argrelextrema(data, np.greater)[0])
min_peaks = list(argrelextrema(data, np.less)[0])# 将极值点拟合为曲线
ipo3_max = spi.splrep(max_peaks, data[max_peaks],k=3) #样本点导入,生成参数
iy3_max = spi.splev(index, ipo3_max) #根据观测点和样条参数,生成插值ipo3_min = spi.splrep(min_peaks, data[min_peaks],k=3) #样本点导入,生成参数
iy3_min = spi.splev(index, ipo3_min) #根据观测点和样条参数,生成插值# 计算平均包络线
iy3_mean = (iy3_max+iy3_min)/2# 绘制图像
plt.figure(figsize = (18,6))
plt.plot(data, label='Original')
plt.plot(iy3_max, label='Maximun Peaks')
plt.plot(iy3_min, label='Minimun Peaks')
plt.plot(iy3_mean, label='Mean')
plt.legend()
plt.xlabel('time (s)')
plt.ylabel('microvolts (uV)')
plt.title("Cubic Spline Interpolation")

用原信号减去平均包络线即为所获得的新信号,若新信号中还存在负的局部极大值和正的局部极小值,说明这还不是一个本征模函数,需要继续进行“筛选”。

获取本征模函数(IMF)

def sifting(data):index = list(range(len(data)))max_peaks = list(argrelextrema(data, np.greater)[0])min_peaks = list(argrelextrema(data, np.less)[0])ipo3_max = spi.splrep(max_peaks, data[max_peaks],k=3) #样本点导入,生成参数iy3_max = spi.splev(index, ipo3_max) #根据观测点和样条参数,生成插值ipo3_min = spi.splrep(min_peaks, data[min_peaks],k=3) #样本点导入,生成参数iy3_min = spi.splev(index, ipo3_min) #根据观测点和样条参数,生成插值iy3_mean = (iy3_max+iy3_min)/2return data-iy3_meandef hasPeaks(data):max_peaks = list(argrelextrema(data, np.greater)[0])min_peaks = list(argrelextrema(data, np.less)[0])if len(max_peaks)>3 and len(min_peaks)>3:return Trueelse:return False# 判断IMFs
def isIMFs(data):max_peaks = list(argrelextrema(data, np.greater)[0])min_peaks = list(argrelextrema(data, np.less)[0])if min(data[max_peaks]) < 0 or max(data[min_peaks])>0:return Falseelse:return Truedef getIMFs(data):while(not isIMFs(data)):data = sifting(data)return data# EMD函数
def EMD(data):IMFs = []while hasPeaks(data):data_imf = getIMFs(data)data = data-data_imfIMFs.append(data_imf)return IMFs# 绘制对比图
data = np.random.random(1000)-0.5
IMFs = EMD(data)
n = len(IMFs)+1# 原始信号
plt.figure(figsize = (18,15))
plt.subplot(n, 1, 1)
plt.plot(data, label='Origin')
plt.title("Origin ")# 若干条IMFs曲线
for i in range(0,len(IMFs)):plt.subplot(n, 1, i+2)plt.plot(IMFs[i])plt.ylabel('Amplitude')plt.title("IMFs "+str(i+1))plt.legend()
plt.xlabel('time (s)')
plt.ylabel('Amplitude')

案例2---利用PyEMD工具来实现EMD

# 导入工具库
import numpy as np
from PyEMD import EMD, Visualisation

构建信号

时间t: 为0到1s,采样频率为100Hz,S为合成信号

# 构建信号
t = np.arange(0,1, 0.01)
S = 2*np.sin(2*np.pi*15*t) +4*np.sin(2*np.pi*10*t)*np.sin(2*np.pi*t*0.1)+np.sin(2*np.pi*5*t)
# 提取imfs和剩余
emd = EMD()
emd.emd(S)
imfs, res = emd.get_imfs_and_residue()
# 绘制 IMF
vis = Visualisation()
vis.plot_imfs(imfs=imfs, residue=res, t=t, include_residue=True)
# 绘制并显示所有提供的IMF的瞬时频率
vis.plot_instant_freq(t, imfs=imfs)
vis.show()

参考:

[1] 基于稳态视觉诱发电位的脑-机接口系统研究

[2]案例1 代码来源于 https://github.com/tianyagk

文章来源于网络,不用于商业行为,若有侵权及疑问,请后台留言!

更多阅读

眼电、脑电视频课程汇总

DIY混合BCI刺激系统:SSVEP-P300 LED刺激

EMD算法之Hilbert-Huang Transform原理详解和案例分析

EEGLAB 使用教程 3 -参考电极和重采样

第2期 | 国内脑机接口领域专家教授汇总

精彩长文 | 脑机接口技术的现状与未来!

ICA处理脑电资料汇总

收藏 | 脑电EEG基础与处理汇总

脑机接口BCI学习交流QQ群:903290195

微信群请扫码添加,Rose拉你进群

手把手教你EMD算法原理与Python实现(更新)相关推荐

  1. EMD算法原理与python实现

    目录 简介 EMD算法原理 python实现EMD案例 本教程为脑机学习者Rose发表于公众号:脑机接口社区 .QQ交流群:903290195 简介 SSVEP信号中含有自发脑电和大量外界干扰信号,属 ...

  2. python numpy安装教程_手把手教你搭建机器学习开发环境—Python与NumPy的超简安装教程...

    手把手教你搭建机器学习开发环境Python语言是机器学习的基础,所以,想要入门机器学习,配置好Python的开发环境是第一步.本文就手把手的教你配置好基于Python的机器学习开发环境.超简单!第一步 ...

  3. python kmeans聚类 对二维坐标点聚类_Kmeans均值聚类算法原理以及Python如何实现

    第一步.随机生成质心 由于这是一个无监督学习的算法,因此我们首先在一个二维的坐标轴下随机给定一堆点,并随即给定两个质心,我们这个算法的目的就是将这一堆点根据它们自身的坐标特征分为两类,因此选取了两个质 ...

  4. 匈牙利算法原理与Python实现

    匈牙利算法原理与Python实现 今天学习一个新的算法-匈牙利算法,用于聚类结果分析,先用图表示我当前遇到的问题: 这两列值是我用不同算法得到的聚类结果,从肉眼可以看出第一列聚类为0的结果在第二列中对 ...

  5. Apriori 算法原理以及python实现详解

    Apriori 算法原理以及python实现 ​ Apriori算法是第一个关联规则挖掘算法,也是最经典的算法.它利用逐层搜索的迭代方法找出数据库中项集的关系,以形成规则,其过程由连接(类矩阵运算)与 ...

  6. LM(Levenberg–Marquardt)算法原理及其python自定义实现

    LM算法原理及其python自定义实现 LM(Levenberg–Marquardt)算法原理 LM算法python实现 实现步骤: 代码: 运行结果: LM(Levenberg–Marquardt) ...

  7. PageRank算法原理与Python实现

    本文转载自https://blog.csdn.net/ten_sory/article/details/80927738 PageRank算法原理与Python实现 PageRank算法,即网页排名算 ...

  8. 手把手教你写专利(2022.12.1更新)

    手把手教你写专利(2022.12.1更新) 一.专利类型 要想发表一篇专利,首要目标是确认专利类型 1.1 发明专利 发明,是指对产品.方法或者其改进所提出的新的技术方案. 如:现有的钢笔是蘸水形成的 ...

  9. python回测函数_【手把手教你】动量指标的Python量化回测

    我认为投资专业的学生只需要两门教授得当的课堂:如何评估一家公司,以及如何考虑市场价格.--巴菲特 01 引言 本文延续"手把手教你使用Python的TA-Lib"系列,以资金流量指 ...

最新文章

  1. Java常用的设计模式总结
  2. 打开高效文本编辑之门_熟悉Linux Sed的替换命令
  3. linux模拟题,Linux操作系统模拟题.doc
  4. CodeForces - 1333C Eugene and an array(尺取)
  5. eclipse怎么导出一个Java项目(莫要错过,最详细教程!)
  6. 软考 - 可靠性和可用性
  7. 使用Bazel编译报错ERROR: Unrecognized option: --experimental_repo_remote_exec解决方法
  8. libjpeg-turbo(1)
  9. 书还可以这样做?3分钟扒光这本变态级作品 | 文末有福利
  10. java 线程一起画图_java 多线程画图 不显示过程
  11. OSI网络模型(TCP/IP五层模型)
  12. 十大经典算法总结(JavaScript描述)
  13. Cisco6500的NAT配置方法
  14. Re0:DP学习之路 01背包如何打印路径?
  15. 传感,驱动,控制-第十章quiz2复习笔记(UTS-41081)
  16. 服务器装win7找不到硬盘驱动,Windows 7安装问题时找不到硬盘驱动器怎么办
  17. 并查集-A Bug's Life(poj2492)
  18. Unity初学者Shader Graph教程
  19. P8195 [传智杯 #4 决赛] 小智的疑惑
  20. 查看电脑支持的最大内存数。

热门文章

  1. uniapp、vue,vuex中state改变,getters不动态改变的完美解决方案!
  2. 解决不同操作系统下git换行符一致性问题
  3. 解决CPC撰写文档报错问题“无法获取“AxforApplication”控件的窗口句柄。不支持无窗口的 ActiveX 控件”
  4. deepin-wine-qq无法加载图片解决方案
  5. 背景颜色的不透明度,但不是文本[重复]
  6. 列表是否包含简短的包含功能?
  7. 删除不再位于远程的跟踪分支
  8. 在django中区分null = True,空白= True
  9. 当用户将鼠标悬停在列表项上时,使光标成为手
  10. CSS基础工作原理(一)——css规则与选择符器