1. VMD
在信号处理中,变分模态分解是一种信号分解估计方法。 该方法在获取分解分量的过程中通过迭代搜寻变分模型最优解来确定每个分量的频率中心和带宽,从而能够自适应地实现信号的频域剖分及各分量的有效分离。
变分模态分解的整体框架是变分问题,使得每个模态的估计带宽之和最小,其中假设每个“模态”是具有不同中心频率的有限带宽,为解决这一变分问题,采用了交替方向乘子法,不断更新各模态及其中心频率,逐步将各模态解调到相应的基频带,最终各个模态即相应的中心频率被一同提取出来。
VMD的目标是将实值输入信号分解成离散数量的子信号,这些子信号在再现输入信号时具有特定的稀疏性。稀疏性体现在谱域的带宽上。 换言之,假设每个子信号主要围绕中心频率,该中心频率将随分解而确定。 VMD具有如下优点:
- 自确定模态分解个数;
- 降低复杂度高和非线性强的时间序列非平稳性;
- 自适应性:在根据实际情况确定所给序列的模态分解个数,随后的搜索和求解过程中可以自适应地匹配每种模态的最佳中心频率和有限带宽,并且可以实现固有模态分量(IMF)2的有效分离、信号的频域划分;
2. VMD包安装
pip install vmdpy
3. 官方VMD源码
def VMD(signal, alpha, tau, K, DC, init, tol):
import numpy as np
import math
import matplotlib.pyplot as plt
save_T=len(signal)
fs=1/float(save_T)
T=save_T
f_mirror=np.zeros(2*T)
f_mirror[0:T//2]=signal[T//2-1::-1]
f_mirror[T//2:3*T//2]= signal
f_mirror[3*T//2:2*T]=signal[-1:-T//2-1:-1]
f=f_mirror
print('-------')
T=float(len(f))
t=np.linspace(1/float(T),1,int(T),endpoint=True)
freqs=t-0.5-1/T
N=500
Alpha=alpha*np.ones(K,dtype=complex)
f_hat=np.fft.fftshift(np.fft.fft(f))
f_hat_plus=f_hat
f_hat_plus[0:int(int(T)/2)]=0
u_hat_plus=np.zeros((N,len(freqs),K),dtype=complex)
omega_plus=np.zeros((N,K),dtype=complex)
if (init==1):
for i in range(1,K+1):
omega_plus[0,i-1]=(0.5/K)*(i-1)
elif (init==2):
omega_plus[0,:]=np.sort(math.exp(math.log(fs))+(math.log(0.5)-math.log(fs))*np.random.rand(1,K))
else:
omega_plus[0,:]=0
if (DC):
omega_plus[0,0]=0
lamda_hat=np.zeros((N,len(freqs)),dtype=complex)
uDiff=tol+2.2204e-16
n=1
sum_uk=0
T=int(T)
while uDiff > tol and n<N:
k=1
sum_uk = u_hat_plus[n-1,:,K-1]+sum_uk-u_hat_plus[n-1,:,0]
u_hat_plus[n,:,k-1]=(f_hat_plus-sum_uk-lamda_hat[n-1,:]/2)/(1+Alpha[k-1]*np.square(freqs-omega_plus[n-1,k-1]))
if DC==False:
omega_plus[n,k-1]=np.dot(freqs[T//2:T],np.square(np.abs(u_hat_plus[n,T//2:T,k-1])).T)/np.sum(np.square(np.abs(u_hat_plus[n,T//2:T,k-1])))
for k in range(2,K+1):
sum_uk=u_hat_plus[n,:,k-2]+sum_uk-u_hat_plus[n-1,:,k-1]
u_hat_plus[n,:,k-1]=(f_hat_plus-sum_uk-lamda_hat[n-1,:]/2)/(1+Alpha[k-1]*np.square(freqs-omega_plus[n-1,k-1]))
omega_plus[n,k-1]=np.dot(freqs[T//2:T],np.square(np.abs(u_hat_plus[n,T//2:T,k-1])).T)/np.sum(np.square(np.abs(u_hat_plus[n,T//2:T:,k-1])))
lamda_hat[n,:]=lamda_hat[n-1,:]+tau*(np.sum(u_hat_plus[n,:,:],axis=1)-f_hat_plus)
n=n+1
uDiff=2.2204e-16
for i in range(1,K+1):
uDiff=uDiff+1/float(T)*np.dot(u_hat_plus[n-1,:,i-1]-u_hat_plus[n-2,:,i-1],(np.conj(u_hat_plus[n-1,:,i-1]-u_hat_plus[n-2,:,i-1])).conj().T)
uDiff=np.abs(uDiff)
N=np.minimum(N,n)
omega = omega_plus[0:N,:]
u_hat = np.zeros((T,K),dtype=complex)
u_hat[T//2:T,:]= np.squeeze(u_hat_plus[N-1,T//2:T,:])
u_hat[T//2:0:-1,:]=np.squeeze(np.conj(u_hat_plus[N-1,T//2:T,:]))
u_hat[0,:]=np.conj(u_hat[-1,:])
u=np.zeros((K,len(t)),dtype=complex)
for k in range(1,K+1):
u[k-1,:]= np.real(np.fft.ifft(np.fft.ifftshift(u_hat[:,k-1])))
u=u[:,T//4:3*T//4]
u_hat = np.zeros((T//2,K),dtype=complex)
for k in range(1,K+1):
u_hat[:,k-1]=np.fft.fftshift(np.fft.fft(u[k-1,:])).conj().T
plt.plot(signal)
plt.show()
for i in range(1,K+1):
plt.plot(u[i-1,:])
plt.show()
return (u,u_hat,omega)
4. 源码解读及使用
4.1 传入参数:
- signal:要分解的信号(一维)
- alpha: 数据保真度约束的平衡参数,经验值为抽样点长度的1.5-2.0倍
- tau: 噪声容限
- K: 要分解模态的数量
- DC:合成的信号若无常量,则取值为0,若含有常量,则取值为1
- init: 初始化w值
初始化为0时,所有的随机数从0开始 初始化为1时,均匀分布产生的随机数; 初始化为2时,随机分布产生的随机数 - tol:控制误差大学常量,决定精度与迭代次数,通常为1e-6左右
4.2 返回参数
- u - 分解后的模态集合
- u_hat - 模态的频谱
- omega - 估计的模态中心频率
4.3 完整代码
from VMD import VMD
import numpy as np
import math
import matplotlib.pyplot as plt
f_1 = 2.0
f_2 = 24.0
f_3 = 288.0
T=1000
t=np.linspace(1/float(T),1,T,endpoint=True)
pi=np.pi
v_1 =np.cos(2*pi*f_1*t)
v_2 = 1/4.0*np.cos(2*pi*f_2*t)
v_3 = 1/16.0*np.cos(2*pi*f_3*t)
alpha = 2000.0
tau = 0
K = 3
DC = 0
init = 1
tol = 1e-7
signal=v_1+v_2+v_3
(u,u_hat,omega)=VMD(signal, alpha, tau, K, DC, init, tol)
print(u.shape)
print(u_hat.shape)
print(omega.shape)
4.4 运行结果
5. 参考信息
K. Dragomiretskiy, D. Zosso, Variational Mode Decomposition, IEEE Trans. on Signal Processing (in press) please check here for update reference: http://dx.doi.org/10.1109/TSP.2013.2288675
|