Hilbert變換提取信號特徵的Python實現

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) ,則有:

希爾伯特變換:
在這裏插入圖片描述
希爾伯特反變換:
在這裏插入圖片描述


上面說的就是初始信號s(t),我們首先把它做一次希爾伯特變換,然後提取特徵值。

都有什麼特徵值呢?

那我們得先補充一個知識點,包絡:隨機過程的振幅隨着時間變化的曲線。也就是信號的振幅與時間(A-t)間的函數關係。

那麼根據不同信號包絡上高階統計量特徵不同,可分爲R值特徵和J值特徵。

信號包絡R值特徵:R值是信號包絡的方差與包絡均值的平方的比值:
在這裏插入圖片描述

信號包絡J值特徵:J值是信號包洛的四階矩和二階矩平方之間的差值與包絡均值的平方的比值:
在這裏插入圖片描述

*雙譜特徵:利用積分的方法將二維雙譜積分函數轉換爲一維雙譜積分函數,從而實現計算方法簡單的積分雙譜:
在這裏插入圖片描述

根據輻射源信號指紋識別技術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特徵值變化圖像:
在這裏插入圖片描述
J特徵值變化圖像:
在這裏插入圖片描述
雙譜圖像:
在這裏插入圖片描述
對於角頻率ω的變化,補充代碼計算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特徵值變化圖像:
在這裏插入圖片描述
J特徵值變化圖像:
在這裏插入圖片描述
雙譜圖像:
在這裏插入圖片描述
對於初始頻率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特徵值變化圖像:
在這裏插入圖片描述

J特徵值變化圖像:
在這裏插入圖片描述
雙譜圖像:
在這裏插入圖片描述


二維的雙譜圖像看起來不是很方便,那麼對圖像進行降維處理,像這種比較對稱的矩陣,用矩陣平均值是最適合的了,這裏只需將希爾伯特變換後的包絡矩陣求下均值,改變下述代碼即可:

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的雙譜特徵變化情況:
在這裏插入圖片描述
角頻率\omega 的雙譜特徵變化情況:
在這裏插入圖片描述
初始頻率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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章