希尔伯特黄变换python实现

希尔伯特变换可以从:
https://zhuanlan.zhihu.com/p/128092836
https://www.cnblogs.com/hdu-zsk/p/4799470.html
等博客学习

python代码如下:

# Author:Administrator
# Name:希尔伯特黄变换
# Time:2023/4/17  12:53
import matplotlib.pyplot as plt
from PyEMD import CEEMDAN, EMD, EEMD
import numpy as np
from scipy.signal import hilbert
from vmdpy import VMD


class HilbertHuangTransform:
    def __init__(self):
        pass

    def __SignalTransfrom(self, x, t=None, name="VMD", alpha=1000, tau=0, K=6, DC=0, init=1, tol=1e-7, max_imf=-1):
        imfs = ""
        if name == "EMD":
            emd = EMD()
            imfs = emd.emd(x, t, max_imf=max_imf)
        elif name == "EEMD":
            emd = EEMD()
            imfs = emd.eemd(x, t, max_imf=max_imf)
        elif name == "CEEMDAN":
            emd = CEEMDAN()
            imfs = emd.ceemdan(x, t, max_imf=max_imf)
        elif name == "VMD":
            u, u_hat, omega = VMD(f=x, alpha=alpha, tau=tau, K=K, DC=DC, init=init, tol=tol)
            imfs = u
        else:
            ValueError(f"{name}不存在")

        return imfs

    def __HilbertTransform(self, imfs):
        """
        希尔伯特变换

        :param imfs: 信号的IMF
        :return:
        """
        analyticSignal = []
        for imf in imfs:
            temp = hilbert(imf)
            analyticSignal.append(temp)
        return np.array(analyticSignal)

    def __CalculateFrequency(self, fs, analyticSignal):
        frequency = []
        amplitude = []
        for signal in analyticSignal:
            # 计算瞬时相位
            angle = np.angle(signal)
            inst_phase = np.unwrap(angle)
            # 计算瞬时幅值
            inst_amp = np.abs(signal)
            amplitude.append(inst_amp)
            # 计算瞬时频率
            inst_freq = np.diff(inst_phase) / (2.0 * np.pi) * fs
            frequency.append(inst_freq)
        return np.array(frequency), np.array(amplitude)

    def __HilbertSpectrum(self, fs, frequency, amplitude, f_bins=500):
        freq_edges = np.linspace(0, fs / 2, f_bins + 1)
        hs = np.zeros((f_bins, frequency.shape[1]))
        for i in range(len(frequency)):
            for j in range(len(frequency[i])):
                f_index = np.digitize(frequency[i][j], freq_edges) - 1
                if f_index >= 0 and f_index < f_bins:
                    hs[f_index, j] += amplitude[i][j]
        return hs, freq_edges

    def run(self, x, fs, t=None, name="VMD", alpha=1000, tau=0, K=5, DC=0, init=1, tol=1e-7, max_imf=5):
        """
        运行程序入口

        :param x: 输入信号
        :param fs: 采样频率
        :param t: 输入信号对应的时间
        :param name: 选择的模型,现有模型有:VMD,EMD,EEMD,CEEMDAN
        :param alpha: 带宽限制 经验取值为 抽样点长度 1.5-2.0 倍;仅对VMD有效
        :param tau: 噪声容限, 表示所有IMF加起来是否等于原始信号,如果等于0,表示必须等于原始信号,否则可以有误差,仅对VMD有效
        :param K: 分解模态(IMF)个数,仅对VMD有效
        :param DC: 合成信号若无常量,取值为 0;若含常量,则其取值为 1;仅对VMD有效
        :param init: 初始化 w 值,当初始化为 1 时,均匀分布产生的随机数;仅对VMD有效
        :param tol: 控制误差大小常量,决定精度与迭代次数,仅对VMD有效
        :param max_imf: EMD,EEMD,CEEMDAN最大分解IMF个数
        :return: frequency, imfs, hs, freq_edges, t
                frequency表示每个IMF的频率
                imfs表示分解的IMF
                hs表示希尔伯特谱值
                freq_edges表示希尔伯特谱值纵坐标
                t表示希尔伯特谱值横坐标
        """
        self.t = t
        imfs = self.__SignalTransfrom(x, t, name, alpha=alpha, tau=tau, K=K, DC=DC, init=init, tol=tol, max_imf=max_imf)
        analyticSignal = self.__HilbertTransform(imfs)
        frequency, amplitude = self.__CalculateFrequency(fs, analyticSignal)
        self.hs, self.freq_edges = self.__HilbertSpectrum(fs, frequency, amplitude)
        return frequency, imfs, self.hs, self.freq_edges, t

    def plot_HilbertSpectrum(self):
        assert not (self.t is None), "t不能是None"
        plt.figure(figsize=(8, 8))
        plt.pcolormesh(self.t, self.freq_edges, self.hs)
        plt.title('Hilbert-Huang Transform')
        plt.show()


if __name__ == "__main__":
    t = np.linspace(0, 1, 10000)
    x = 12*np.cos(np.pi*2*20*t) + 8*np.cos(np.pi*2*100*t) + 30*np.cos(np.pi*2*2000*t)
    x1 = [0]*5000
    x1 = np.append(x1, 20*np.sin(np.pi*2*500*t[5000:]))
    x_noise = x1 + x

    hht = HilbertHuangTransform()
    hht.run(x_noise, 10000, t, alpha=int(1*len(t)), name="CEEMDAN")
    hht.plot_HilbertSpectrum()


使用20Hz、100Hz、2000Hz以及500Hz叠加信号进行希尔伯特黄变换得到希尔伯特谱,其中500Hz信号实在0.5s之后进行添加的,采样频率为10000Hz,时间范围为0-1s,没有加噪声,其变换结果如下:
在这里插入图片描述
可以看出基本可以,区分出来不同频率谁时间变化情况。

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值