标签(空格分隔): 数学

这一篇写一下变分模态分解(原始论文:Variational Mode Decomposition),跟原始论文思路思路一致但有一点点不太一样,原始论文写的很好,但我不是通信专业没有学过信号相关课程一开始看起来有点费劲。模态分解认为信号是由不同“模态”的子信号叠加而成的,而变分模态分解则认为信号是由不同频率占优的子信号叠加而成的,其目的是要把信号分解成不同频率的子信号。变分模态分解的分解结果如图所示

基础

一开始论文看不懂的原因是缺少相关前置知识,但一旦顺下来就会感觉其实没有那么难,难的是作者的思路很巧妙,先写下我遇到的这些知识盲点

第一点是傅立叶变换的微分性质,

的傅立叶变换为

,其导数

的傅立叶变换为

另一点是解析信号,现实世界只能采集实信号,但实信号有很多不好用的性质,如存在负频率,无法直接得到调制频率后的实信号等。 设原始信号是一个实信号

为了方便表示

为随

变化的函数,相当于瞬时频率,解析信号是一个复信号,可以通过希尔伯特变换得到

解析信号的实部是原本的实数信号,并且经过调频之后复数信号的实部仍然是调频之后的实信号,如对信号

增加频率

,只需要乘以

即可

由此,其实部相当于在原本频率

的基础上增加了频率

,如下面的matlab脚本

clear;close all;clc;

t = 1:0.01:10;

%%

f1 = sin(20*t).*(t-5).^2;

subplot(3,1,1);

plot(f1);

ylim([-25 25]);

%%

f2 = sin(50*t).*(t-5).^2;

subplot(3,1,2);

plot(f2);

ylim([-25 25]);

%%

H = hilbert(f1);

f_hat = H.*exp(1i*30.*t);

subplot(3,1,3);

plot(real(f_hat));

ylim([-25 25]);

matlab的hilbert函数包括希尔伯特变换和解析函数转换两部分,直接得到实信号的解析信号,其中希尔伯特变换

正文

接下来我们看看如何一步一步得到变分模态分解的思路

原论文通过一个信号降噪问题进行说明,现需要对采样信号

进行降噪重构,假设观测信号是由原始信号叠加一个独立的高斯噪音

,需要求

,又说该等式是一个不适定问题(ill-posed problem),不满足识定问题的三个条件,所以要用一个正则化的方法

第一部分是对原信号进行重构,第二部分是为了解决不适定问题的解不唯一,而且不同于机器学习的建模问题一样

是一个权值形式可以直接加权值

的L1-norm或L2-norm,这里的

是一个纯函数的形式,其导数的L2-norm最小化感觉上应该是保证了函数

不会产生太大的波动,这里可不可以跟防止过拟合联系起来,接下来说明这个约束会使

在频率域产生什么影响。

下面解这个式子,首先来看一下直接最小化泛函

能不能解出来

,然后根据E-L方程的引理

,往下忘了怎么求了。。。。。想起来怎么求再继续写-_-!,这个直接求的方法与原文没什么关系的

由上面的傅立叶变换的微分性质知道,用傅立叶变换在复数域很方便可以把微分约掉,而且还有一个叫什么Plancherel傅立叶等距映射的东西,时域的L2范数与傅立叶变换到的频率域的L2范数等距,故上面的最小化的项可以直接用傅立叶变换转换到频域

,这里需要注意的是利用上面的那个什么等距定理有

是同一个

,这一点很重要,第二个是L2范数大于0,则把其展开为泛函

求最极值,由于这里面只有

直接求偏导即可也不用解微分方程

可以看到得到的

相当于对观测信号在

在频率段进行滤波,过滤掉了高频部分,这说明加了该导数的L1正则约束与上面的直观感觉是一样的,过滤掉了高频部分,减弱

的波动

再往下进行,模态分解需要把原始信号分解成多个子信号的和,我们为了和原文对应修改一下符号表示,

表示观测的采样信号,

表示分解得到的基函数,则上面的约束对象变为

同样先转化为频率域再求极值

泛函

每个基函数基于其他的基函数更新,相当于每个基函数是原信号剩余部分的低通滤波,每次迭代都是保留剩余信号的低频率部分。

到现在为止我们发现每个基函数都会趋向于每次的剩余信号分量的低频部分,这与我们原始的假设“每个基函数都有不同的频率分量”是相悖的,但根据上面的低通滤波的性质,每个基函数进行特定频率的滤波应该就能解决这个问题了,那么上面的式子就简单的变为

其中,

为每个基函数

的中心频率,该式就是变分模态分解的基函数的更新公式,我们来看一下这个式子应该如何得到,以便于找到中心频率的更新公式

由上面的一步一步的演化发现,基函数对剩余信号的低通滤波是由导数的L2正则最小化带来的,要得到基函数的中心频率约束也要从这个地方入手,由上面的推导可知每个基函数都会被约束到

频率附近,那么我们把基函数的频率增加各自的中心频率

得到

,并保证

即可,则相当于对每个基函数乘以了一个

,这里需要对频率进行变换,我们沿用文章开头的解析信号的性质,认为

是一个复数的解析信号,同样也需要把观测信号

预先转化为解析信号,下文默认都是解析信号,则每一个基函数转换频率后的导数变为

傅立叶变换得

先来看看傅立叶变换为什么会得到这个,而不是

反傅立叶变换

感觉应该不是这样证的,我数学不是很好,不怎么会这个变量变换

至此,约束变为

傅立叶变换

根据论文原文把

然后求最小就可以得到上面

的更新公式

最后,为了保证每个点处的重构信号与原信号尽可能相似,增加了每个点处的重构约束,其实这一项并不是必需的,最终的约束对象为

,然后拉格朗日乘子法带进去,但其需要满足下式才有意义

这个式子还是符合Parseval定理,故整理一下

最后整理一下更新公式:

其中

使用梯度下降更新

代码

%matplotlib inline

from matplotlib import pyplot as plt

import numpy as np

from scipy.signal import hilbert

T = 1000

fs = 1./T

t = np.linspace(0, 1, 1000,endpoint=True)

f_1 = 10

f_2 = 50

f_3 = 100

mode_1 = (2 * t) ** 2

mode_2 = np.sin(2 * np.pi * f_1 * t)

mode_3 = np.sin(2 * np.pi * f_2 * t)

mode_4 = np.sin(2 * np.pi * f_3 * t)

f = mode_1 + mode_2 + mode_3 + mode_4 + 0.5 * np.random.randn(1000)

plt.figure(figsize=(6,3), dpi=150)

plt.plot(f, linewidth=1)

class VMD:

def __init__(self, K, alpha, tau, tol=1e-7, maxIters=200, eps=1e-9):

""":param K: 模态数:param alpha: 每个模态初始中心约束强度:param tau: 对偶项的梯度下降学习率:param tol: 终止阈值:param maxIters: 最大迭代次数:param eps: eps"""

self.K =K

self.alpha = alpha

self.tau = tau

self.tol = tol

self.maxIters = maxIters

self.eps = eps

def __call__(self, f):

T = f.shape[0]

t = np.linspace(1, T, T) / T

omega = t - 1. / T

# 转换为解析信号

f = hilbert(f)

f_hat = np.fft.fft(f)

u_hat = np.zeros((self.K, T), dtype=np.complex)

omega_K = np.zeros((self.K,))

lambda_hat = np.zeros((T,), dtype=np.complex)

# 用以判断

u_hat_pre = np.zeros((self.K, T), dtype=np.complex)

u_D = self.tol + self.eps

# 迭代

n = 0

while n < self.maxIters and u_D > self.tol:

for k in range(self.K):

# u_hat

sum_u_hat = np.sum(u_hat, axis=0) - u_hat[k, :]

res = f_hat - sum_u_hat

u_hat[k, :] = (res + lambda_hat / 2) / (1 + self.alpha * (omega - omega_K[k]) ** 2)

# omega

u_hat_k_2 = np.abs(u_hat[k, :]) ** 2

omega_K[k] = np.sum(omega * u_hat_k_2) / np.sum(u_hat_k_2)

# lambda_hat

sum_u_hat = np.sum(u_hat, axis=0)

res = f_hat - sum_u_hat

lambda_hat -= self.tau * res

n += 1

u_D = np.sum(np.abs(u_hat - u_hat_pre) ** 2)

u_hat_pre[::] = u_hat[::]

# 重构,反傅立叶之后取实部

u = np.real(np.fft.ifft(u_hat, axis=-1))

omega_K = omega_K * T

idx = np.argsort(omega_K)

omega_K = omega_K[idx]

u = u[idx, :]

return u, omega_K

K = 4

alpha = 2000

tau = 1e-6

vmd = VMD(K, alpha, tau)

u, omega_K = vmd(f)

omega_K

# array([0.85049797, 10.08516203, 50.0835613, 100.13259275]))

plt.figure(figsize=(5,7), dpi=200)

plt.subplot(4,1,1)

plt.plot(mode_1, linewidth=0.5, linestyle='--')

plt.plot(u[0,:], linewidth=0.2, c='r')

plt.subplot(4,1,2)

plt.plot(mode_2, linewidth=0.5, linestyle='--')

plt.plot(u[1,:], linewidth=0.2, c='r')

plt.subplot(4,1,3)

plt.plot(mode_3, linewidth=0.5, linestyle='--')

plt.plot(u[2,:], linewidth=0.2, c='r')

plt.subplot(4,1,4)

plt.plot(mode_4, linewidth=0.5, linestyle='--')

plt.plot(u[3,:], linewidth=0.2, c='r')

# []

可以看到有比较强的端点效应,端点处会有重叠,文章原始论文中采用的方法是对称拼接的方法,把原信号复制一份然后拼成两半,一半对称放前面,一般对称放后面

%matplotlib inline

from matplotlib import pyplot as plt

import numpy as np

from scipy.signal import hilbert

T = 1000

fs = 1./T

t = np.linspace(0, 1, 1000,endpoint=True)

f_1 = 10

f_2 = 50

f_3 = 100

mode_1 = np.sin(2 * np.pi * f_1 * t)

mode_2 = np.sin(2 * np.pi * f_2 * t)

mode_3 = np.sin(2 * np.pi * f_3 * t)

f = np.concatenate((mode_1[:301], mode_2[301:701], mode_3[701:])) + 0.1 * np.random.randn(1000)

plt.figure(figsize=(6,3), dpi=150)

plt.plot(f, linewidth=0.5)

# []

class VMD:

def __init__(self, K, alpha, tau, tol=1e-7, maxIters=200, eps=1e-9):

""":param K: 模态数:param alpha: 每个模态初始中心约束强度:param tau: 对偶项的梯度下降学习率:param tol: 终止阈值:param maxIters: 最大迭代次数:param eps: eps"""

self.K =K

self.alpha = alpha

self.tau = tau

self.tol = tol

self.maxIters = maxIters

self.eps = eps

def __call__(self, f):

N = f.shape[0]

# 对称拼接

f = np.concatenate((f[:N//2][::-1], f, f[N//2:][::-1]))

T = f.shape[0]

t = np.linspace(1, T, T) / T

omega = t - 1. / T

# 转换为解析信号

f = hilbert(f)

f_hat = np.fft.fft(f)

u_hat = np.zeros((self.K, T), dtype=np.complex)

omega_K = np.zeros((self.K,))

lambda_hat = np.zeros((T,), dtype=np.complex)

# 用以判断

u_hat_pre = np.zeros((self.K, T), dtype=np.complex)

u_D = self.tol + self.eps

# 迭代

n = 0

while n < self.maxIters and u_D > self.tol:

for k in range(self.K):

# u_hat

sum_u_hat = np.sum(u_hat, axis=0) - u_hat[k, :]

res = f_hat - sum_u_hat

u_hat[k, :] = (res + lambda_hat / 2) / (1 + self.alpha * (omega - omega_K[k]) ** 2)

# omega

u_hat_k_2 = np.abs(u_hat[k, :]) ** 2

omega_K[k] = np.sum(omega * u_hat_k_2) / np.sum(u_hat_k_2)

# lambda_hat

sum_u_hat = np.sum(u_hat, axis=0)

res = f_hat - sum_u_hat

lambda_hat -= self.tau * res

n += 1

u_D = np.sum(np.abs(u_hat - u_hat_pre) ** 2)

u_hat_pre[::] = u_hat[::]

# 重构,反傅立叶之后取实部

u = np.real(np.fft.ifft(u_hat, axis=-1))

u = u[:, N//2 : N//2 + N]

omega_K = omega_K * T / 2

idx = np.argsort(omega_K)

omega_K = omega_K[idx]

u = u[idx, :]

return u, omega_K

K = 3

alpha = 2000

tau = 1e-6

vmd = VMD(K, alpha, tau)

u, omega_K = vmd(f)

omega_K

# array([ 9.68579292, 50.05232833, 100.12321047])

plt.figure(figsize=(5,7), dpi=200)

plt.subplot(3,1,1)

plt.plot(mode_1, linewidth=0.5, linestyle='--')

plt.plot(u[0,:], linewidth=0.2, c='r')

plt.subplot(3,1,2)

plt.plot(mode_2, linewidth=0.5, linestyle='--')

plt.plot(u[1,:], linewidth=0.2, c='r')

plt.subplot(3,1,3)

plt.plot(mode_3, linewidth=0.5, linestyle='--')

plt.plot(u[2,:], linewidth=0.2, c='r')

# []

好像结果要好一点,VMD的一个缺点是K的值对结果有很大影响,但这个迭代过程,怎么开始怎么迭代怎么结束都可以自己控制,感觉可以按照自己的需求来定制怎么动态决定K

变分模态分解 python_Variational Mode Decomposition (变分模态分解)相关推荐

  1. C#,数值计算,矩阵的乔莱斯基分解(Cholesky decomposition)算法与源代码

    一.安德烈·路易斯·乔尔斯基 安德烈·路易斯·乔尔斯基出生于法国波尔多以北的查伦特斯海域的蒙古扬.他在波尔多参加了Lycée e,并于1892年11月14日获得学士学位的第一部分,于1893年7月24 ...

  2. 多元经验模态分解_环境激励桥梁模态参数识别—环境激励模态参数识别概述

    环境激励模态参数识别概述 1 结构模态参数识别 结构模态参数识别属于动力学的反问题,是利用外部激励和系统的响应求解系统的参数问题;这一过程亦称为模态分析(Modal Analysis).模态分析又分为 ...

  3. 3点 刚体运动 opencv_模态法动力学分析中的刚体模态

    01 - 概述 在对汽车结构进行动力学有限元分析时,无论是瞬态问题还是频响问题,都经常使用模态叠加法. 模态叠加法动力学分析是常规模态分析的自然扩展,它利用结构振型来缩减问题求解规模,从而使数值求解更 ...

  4. 【自然语言处理系列】自编码器AE、变分自编码器VAE和条件变分自编码器CVAE

    作者:CHEONG 公众号:AI机器学习与知识图谱 研究方向:自然语言处理与知识图谱 本文主要分享自编码器.变分自编码器和条件变分自编码器的相关知识以及在实际实践中的应用技巧,原创不易转载请注明出处, ...

  5. 基于C++的本征图像分解(Intrinsic Image Decomposition)

    利用本征图像分解(Intrinsic Image Decomposition)算法,将图像分解为shading(illumination) image 和 reflectance(albedo) im ...

  6. html弹窗赋值给查询框,bootstrap模态框动态赋值, ajax异步请求数据后给id为queryInfo的模态框赋值并弹出模态框(JS)...

    /查询单个 function query(id) { $.ajax({ url : "/small/productServlet", async : true, type : &q ...

  7. 矩阵分解(rank decomposition)文章代码汇总

    矩阵分解(rank decomposition) 本文收集了现有矩阵分解的几乎所有算法和应用,原文链接:https://sites.google.com/site/igorcarron2/matrix ...

  8. C++ Heavy Light Decomposition重轻分解的实现算法(附完整源码)

    C++Heavy Light Decomposition重轻分解的实现算法 C++Heavy Light Decomposition重轻分解的实现算法完整源码(定义,实现,main函数测试) C++H ...

  9. Bootstrap开启模态框后对数据处理(标记模态框的开启与关闭状态)

    JS用全局变量标记状态,方法中动态修改全局变量以标记状态是一个重要思想. 需求:组合条件查询数据,查询完之后填充到模态框中,开启模态框,模态框中有组合条件查询,此时查询只需要更新模态框表格数据不需要开 ...

  10. 来个模态kuang_使用 React 制作一个模态框

    使用 React 制作一个模态框 模态框是一个常见的组件,下面让我们使用 React 实现一个现代化的模态框吧. 组件设计 模态框想必大家都很熟悉,是工作中常用的组件,可以让我们填写或展示一些信息而不 ...

最新文章

  1. 浅浅认识之VBS脚本访问接口与COMODO拦截COM接口
  2. Unity旋转问题的总结
  3. 上帝给你关闭一道门,就会为你打开一扇窗,反推。
  4. 4.5 matlab三维曲面(mesh、fmesh、meshc、meshz、surf、fsurf、surfc、surfl)
  5. 20165231 2017-2018-2 《Java程序设计》第5周学习总结
  6. Spring事务回滚和异常类
  7. 数据挖掘:数据仓库相关知识笔记
  8. 最大 / 小的K个数
  9. php中abs,php中的abs函数怎么用
  10. 1.vue生命周期详解(2020.12.05)
  11. 在Eclipse中打jar包
  12. HDAO 全新项目落地,带动区块链新一轮牛市
  13. 外贸最全出口流程,外贸必看基础知识
  14. linux终端网易云播放问题,Ubuntu下完美解决网易云音乐无法启动的问题
  15. c语言中比较两束大小,【 C 语言吧 · 文学 · 西游记 】
  16. ImageJ自动批量荧光面积统计
  17. 卸载chrome浏览器_如何在Chrome,Firefox和其他浏览器中卸载扩展程序
  18. MySql now函数
  19. 单页双曲面 matlab,生成平面截单叶双曲面的gif动画的程序
  20. idea debug图解

热门文章

  1. catia怎么进入装配_catia怎么装配步骤
  2. C/C++中的位运算
  3. Linux使用进程id跟踪程序,使用linux的pidof命令返回运行程序的进程ID
  4. Qt::QWidget 无默认标题栏边框的拖拽修改大小方式
  5. 【云原生 | Docker篇】 Docker容器配置阿里云镜像加速器
  6. 一键搞定JavaEE应用 JRE+Tomcat+Mysql-JaveEE绿色运行环境JTM0 9版
  7. java源程序编译的结果_java源程序编译后
  8. java编译异常有哪些_java编译时异常有哪些?java常见异常有哪些?
  9. 华为云NP考试题库_华为认证考试题库-HCNP
  10. linux的视频格式转换软件,工具盘点:必备的Linux视频转换工具(1)