Hilbert变换提取信号特征的Python实现

开篇点题:

希尔伯特变换(hilbert transform) 一个连续时间信号s(t)的希尔伯特变换等于该信号通过具有冲激响应h(t)=1/πt的线性系统以后的输出响应sh(t)。

好的,这是Hilbert变换的定义,我们这里讨论它的一个具体用途,提取信号特征值,提取信号特征值有什么用呢?

先来一段特征值的定义:

设 A 是n阶方阵,如果存在数m和非零n维列向量 x,使得 Ax=mx 成立,则称 m 是A的一个特征值或本征值。

所以信号特征值可以用来代替一段信号对系统产生的影响,或者说取代一段信号并填补它功能的空缺,我们按照这个思想,在外界或内部改变信号的某些条件之后,可以用特征值随外界或内部因素的变化图像来反映干扰因素对信号的影响,或者反映信号本身对外界干扰的抵抗力及自身的稳定性、鲁棒性等性质。

那么具体怎么用呢?设有一个实值函数s(t),其希尔伯特反变换记作\hat{s}(t) ,则有:

希尔伯特变换:

(1)

希尔伯特反变换:

(2)

上面说的就是初始信号s(t),我们首先把它做一次希尔伯特变换,然后提取特征值。

都有什么特征值呢?

那我们得先补充一个知识点,包络:随机过程的振幅随着时间变化的曲线。也就是信号的振幅与时间(A-t)间的函数关系。

那么根据不同信号包络上高阶统计量特征不同,可分为R值特征和J值特征。

信号包络R值特征:R值是信号包络的方差与包络均值的平方的比值:

(3)

信号包络J值特征:J值是信号包洛的四阶矩和二阶矩平方之间的差值与包络均值的平方的比值:

(4)

*双谱特征:利用积分的方法将二维双谱积分函数转换为一维双谱积分函数,从而实现计算方法简单的积分双谱:

(5)

根据辐射源信号指纹识别技术http://xueshu.baidu.com/usercenter/paper/show?paperid=f2c7b987bd3af320909da0e1c09a723b&site=xueshu_se,这篇论文,三种特征值能够很好的表现信号性能。

好了,基础的知识就是这些,下面我们写代码实现Hilbert变换,计算并提取三种特征值。

import numpy as np 

from math import pi 

import matplotlib.pyplot as plt 

import math 

from scipy import fftpack 

from sklearn import preprocessing 

import neurolab as nl 

# 码元数 

size = 10 

sampling_t = 0.01 

t = np.arange(0, size, sampling_t) 

#随机生成信号序列 

a = np.random.randint(0, 2, size)  #产生随机整数序列 

m = np.zeros(len(t), dtype=np.float32)    #产生一个给定形状和类型的用0填充的数组 

for i in range(len(t)): 

    m[i] = a[int(math.floor(t[i]))] 

ts1 = np.arange(0, (np.int64(1/sampling_t) * size))/(10*(m+1)) 

fsk = np.cos(np.dot(2 * pi, ts1) + pi / 4) 

def awgn(y, snr):      #snr为信噪比dB值 

    snr = 10 ** (snr / 10.0) 

    xpower = np.sum(y ** 2) / len(y) 

    npower = xpower / snr 

    return np.random.randn(len(y)) * np.sqrt(npower) + y 

def feature_rj(y):        #[feature1, f2, f3] = rj(noise_bpsk, fs) 

    h = fftpack.hilbert(y)  # hilbert变换 

    z = np.sqrt(y**2 + h**2)  # 包络 

    m2 = np.mean(z**2)    # 包络的二阶矩 

    m4 = np.mean(z**4)    # 包络的四阶矩 

    r = abs((m4-m2**2)/m2**2) 

    Ps = np.mean(y**2)/2 

    j = abs((m4-2*m2**2)/(4*Ps**2)) 

    return (r,j) 

def feature_Bispectrum(y): 

    ly = size  # 行数10 

    nrecs = np.int64(1 / sampling_t)  # 列数100 

    nlag = 20 

    nsamp = nrecs  # 每段样本数100 

    nrecord = size 

    nfft = 128 

    Bspec = np.zeros((nfft, nfft), dtype=np.float32) 

    y = y.reshape(ly, nrecs) 

    c3 = np.zeros((nlag + 1, nlag + 1), dtype=np.float32) 

    ind = np.arange(nsamp) 

    for k in range(nrecord): 

        x = y[k][ind] 

        x = x - np.mean(x) 

        for j in range(nlag + 1): 

            z = np.multiply(x[np.arange(nsamp - j)], x[np.arange(j, nsamp)]) 

            for i in range(j, nlag + 1): 

                sum = np.mat(z[np.arange(nsamp - i)]) * np.mat(x[np.arange(i, nsamp)]).T 

                sum = sum / nsamp 

                c3[i][j] = c3[i][j] + sum  # i,j顺序 

    c3 = c3 / nrecord 

    c3 = c3 + np.mat(np.tril(c3, -1)).T  # 取对角线以下三角,c3为矩阵 

    c31 = c3[1:, 1:] 

    c32 = np.mat(np.zeros((nlag, nlag), dtype=np.float32)) 

    c33 = np.mat(np.zeros((nlag, nlag), dtype=np.float32))  # 不可以直接3者相等 

    c34 = np.mat(np.zeros((nlag, nlag), dtype=np.float32)) 

    for i in range(nlag): 

        x = c31[i:, i] 

        c32[nlag - 1 - i, 0:nlag - i] = x.T 

        c34[0:nlag - i, nlag - 1 - i] = x 

        if i < (nlag - 1): 

            x = np.flipud(x[1:, 0])  # 上下翻转,翻转后依然为矩阵 

            c33 = c33 + np.diag(np.array(x)[:, 0], i + 1) + np.diag(np.array(x)[:, 0], -(i + 1)) 

    c33 = c33 + np.diag(np.array(c3)[0, :0:-1]) 

    cmat = np.vstack((np.hstack((c33, c32, np.zeros((nlag, 1), dtype=np.float32))), 

                      np.hstack((np.vstack((c34, np.zeros((1, nlag), dtype=np.float32))), c3))))          #41*41 

    Bspec = fftpack.fft2(cmat, [nfft, nfft])     

    Bspec = np.fft.fftshift(Bspec)                #128*128 

    waxis = np.arange(-nfft / 2, nfft / 2) / nfft 

    X, Y = np.meshgrid(waxis, waxis) 

    plt.contourf(X, Y, abs(Bspec),alpha=0,cmap=plt.cm.hot) 

    plt.contour(X, Y, abs(Bspec)) 

    plt.show() 

    return Bspec 

def features(s): 

#    for mc in range(2): 

        snr = np.random.uniform(0, 20)      #从一个均匀分布集合中随机采样,左闭右开--[low,high) 

        s = awgn(s,snr)            #在原始信号的基础上增加SNR信噪比的噪音 

        rj = np.array(feature_rj(s))              #计算R,J特征 

        z = feature_Bispectrum(s)                  #计算双谱特征,并画图像 

        xx = np.int64(np.sqrt(np.size(z))/2) 

        z = np.array(z[:xx,xx:]) 

        z = np.tril(z).real              #取复数z的实部 

        bis = np.zeros((1, xx),dtype=np.float32)    #零组 

        for i in range(xx): 

            for j in range(xx-i): 

                bis[0][i] = bis[0][i]+z[xx-1-j][i+j] 

        m = bis[0].reshape(1,xx) 

        normalized = preprocessing.normalize(m)[0,:]    #样本各个特征值除以各个特征值的平方之和 

        features = np.hstack((rj,normalized))          #合并数组r,j和normalized 

        return features 

print(features(fsk)) 

好的,特征值已经有了,那么下面我们怎么使用这些特征值来描述初始信号的变化趋势呢?

画出特征值曲线是个不错的办法,趋势一目了然,为了说明信号受到影响,我们分别从信号的振幅A,角频率\omega ,初始频率S的改变来说明问题。初始信号图像如下:

初始信号图像

为了统一起见,我们分别另A,\omega ,S从0到2\Pi 均匀变化,对于振幅A的变化,补充代码计算R,J特征值,画出双谱图:

R = []

J = [] 

ts1 = np.arange(0, (np.int64(1/sampling_t) * size))/(10*(m+1)) 

W = [] 

Z = [] 

for i in range(0,40,1): 

    W.append(i / (2 * pi)) 

for a1 in W: 

    global r,j 

    fsk = a1 * np.cos(np.dot(2 * pi, ts1) + pi / 4) 

    features(fsk) 

    R.append(r) 

    J.append(j) 

plt.plot(W, R, color='green', label='1') 

plt.legend() # 显示图例 

plt.xlabel('A[0-2 * pi]') 

plt.ylabel('R') 

plt.show() 

plt.plot(W, J, color='red', label='2') 

plt.legend() # 显示图例 

plt.xlabel('A[0-2 * pi]') 

plt.ylabel('J') 

plt.show() 

plt.plot(W, Z, color='red', label='3') 

plt.legend() # 显示图例 

plt.xlabel('A[0-2 * pi]') 

plt.ylabel('trend') 

plt.show() 

R特征值变化图像:

R特征值变化A

J特征值变化图像:

J特征值变化A

双谱图像:

双谱A

对于角频率ω的变化,补充代码计算R,J特征值,画出R、J、双谱图像:

R = []

J = [] 

ts1 = np.arange(0, (np.int64(1/sampling_t) * size))/(10*(m+1)) 

W = [] 

Z = [] 

for i in range(0,40,1): 

    W.append(i / (2 * pi)) 

for w in W: 

    global r,j 

    fsk = np.cos(np.dot(w, ts1) + pi / 4) 

    features(fsk) 

    R.append(r) 

    J.append(j) 

plt.plot(W, R, color='green', label='1') 

plt.legend() # 显示图例 

plt.xlabel('w[0-2 * pi]') 

plt.ylabel('R') 

plt.show() 

plt.plot(W, J, color='red', label='2') 

plt.legend() # 显示图例 

plt.xlabel('w[0-2 * pi]') 

plt.ylabel('J') 

plt.show() 

plt.plot(W, Z, color='red', label='3') 

plt.legend() # 显示图例 

plt.xlabel('A[0-2 * pi]') 

plt.ylabel('trend') 

plt.show() 

R特征值变化图像:

R特征值变化\omega

J特征值变化图像:

J特征值变化\omega

双谱图像:

双谱\omega

对于初始频率S的变化,补充代码计算R,J特征值,画出双谱图:

R = []

J = [] 

ts1 = np.arange(0, (np.int64(1/sampling_t) * size))/(10*(m+1)) 

W = [] 

Z = [] 

for i in range(0,40,1): 

    W.append(i / (2 * pi)) 

for s in W: 

    global r,j 

    fsk = np.cos(np.dot(2 * pi, ts1) + s) 

    features(fsk) 

    R.append(r) 

    J.append(j) 

plt.plot(W, R, color='green', label='1') 

plt.legend() # 显示图例 

plt.xlabel('s[0-2 * pi]') 

plt.ylabel('R') 

plt.show() 

plt.plot(W, J, color='red', label='2') 

plt.legend() # 显示图例 

plt.xlabel('s[0-2 * pi]') 

plt.ylabel('J') 

plt.show() 

plt.plot(W, Z, color='red', label='3') 

plt.legend() # 显示图例 

plt.xlabel('A[0-2 * pi]') 

plt.ylabel('trend') 

plt.show() 

R特征值变化图像:

R特征值变化S

J特征值变化图像:

J特征值变化S

双谱图像:

双谱S

二维的双谱图像看起来不是很方便,那么对图像进行降维处理,像这种比较对称的矩阵,用矩阵平均值是最适合的了,这里只需将希尔伯特变换后的包络矩阵求下均值,改变下述代码即可:

Bspec = fftpack.fft2(cmat, [nfft, nfft])

Bspec = np.fft.fftshift(Bspec)                #128*128 

waxis = np.arange(-nfft / 2, nfft / 2) / nfft 

X, Y = np.meshgrid(waxis, waxis) 

plt.contourf(X, Y, abs(Bspec)) 

plt.contour(X, Y, abs(Bspec)) 

Z.append(np.mean(abs(Bspec))) 

则双谱特征降维后图像如下,振幅A的双谱特征变化情况:

双谱降维A

角频率\omega 的双谱特征变化情况:

双谱降维\omega

初始频率S的双谱特征变化情况:

双谱降维S

文章能看到最后真的很不容易,代码以及部分延伸已上传到GitHub及Gitee上,求star:

GitHub:https://github.com/wangwei39120157028/Signal_Feature_Extraction/

Gitee:https://gitee.com/wwy2018/Signal_Feature_Extraction

欢迎再到我的GitHub和Gitee上看看我的关于逆向工程的项目(是Gitee推荐哦),点赞求星。

GitHub:https://github.com/wangwei39120157028/IDAPythonScripts

Gitee:https://gitee.com/wwy2018/IDAPythonScripts

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容