小波,就是很小的波,它的積分總是接近於 0;
小波 又分為 小波分解 和 小波包分解;
小波分解 只對 低頻部分 進行分解,對高頻部分不再分解,所以能夠過濾掉 高頻部分;
低頻部分 代表了 趨勢,也叫 近似信號;高頻部分 代表了 噪聲,也叫 細節信號;
小波包分解 則既對 低頻部分 進行分解,也對 高頻部分 進行分解;
對小波的理解
小波變換 就是把 一個波形 分解成 N個 低頻部分 和 M個 高頻部分 的 和;
同一個小波基函數可以通過 平移和縮放 生成不同的小波基;
小波變換就是 把 原始信號 與 小波基函數 以及 尺度函數 進行內積運算,所以一個 小波基 和一個 尺度函數 就確定了一個小波變換;
類比理解:小波基 就相當於 一個 標准正交基;原始信號 與 小波基 作內積 相當於 向量在 標准正交基上做投影;
Python 小波用法
CWT:連續的小波變換
DWT:離散的小波變換
安裝
pip install PyWavelets
查看所有小波族
import pywt print(pywt.families()) # 查看所有小波基 # ['haar', 'db', 'sym', 'coif', 'bior', 'rbio', 'dmey', 'gaus', 'mexh', 'morl', 'cgau', 'shan', 'fbsp', 'cmor'] print(pywt.families(short=False)) # ['Haar', 'Daubechies', 'Symlets', 'Coiflets', 'Biorthogonal', 'Reverse biorthogonal', 'Discrete Meyer (FIR Approximation)', 'Gaussian', 'Mexican hat wavelet', 'Morlet wavelet', 'Complex Gaussian wavelets', 'Shannon wavelets', 'Frequency B-Spline wavelets', 'Complex Morlet wavelets']
離散 1D 小波變換
1D 多階小波變換 wavedec
def wavedec(data, wavelet, mode='symmetric', level=None, axis=-1): """ Multilevel 1D Discrete Wavelet Transform of data. wavelet : Wavelet object or name string 小波基 Wavelet to use mode : str, optional 默認是對稱的 Signal extension mode, see :ref:`Modes <ref-modes>`. level : int, optional Decomposition level (must be >= 0). If level is None (default) then it will be calculated using the ``dwt_max_level`` function. axis: int, optional Axis over which to compute the DWT. If not given, the last axis is used. Returns ------- [cA_n, cD_n, cD_n-1, ..., cD2, cD1] : list
level 指定了 分解 階數
返回的是 各層的小波系數 【也就是 特征值,一個 信號 分解為 多個 波形,每個 波形 對應一個 小波系數,計算 這個小波系數 的范數,就是這個 波形 對應的 能量】
示例
import numpy as np from pywt import wavedec import matplotlib.pylab as plt np.random.seed(10) data = np.random.random((100, )) coeffs = wavedec(data, 'db1', level=2) # 一維離散信號的小波變換 cA2, cD2, cD1 = coeffs # 一個低頻,多個高頻,高頻數 取決於 level plt.subplot(411); plt.title('original'); plt.plot(data) plt.subplot(412); plt.title('ca2'); plt.plot(cA2) plt.subplot(413); plt.title('cd2'); plt.plot(cD2) plt.subplot(414); plt.title('cd1'); plt.plot(cD1) plt.show()
1D 1 階小波分解
level = 2 相當於 進行了 2 次 1階小波分解
def dwt(data, wavelet, mode='symmetric', axis=-1)
可以看到 沒有 level 參數,level 恆為 1
與 wavedec 進行比對,指定 wavedec level=2,結果相同
np.random.seed(10) data = np.random.random((10, )) coeffs = wavedec(data, 'db1', level=2) # 一維離散信號的小波變換 cA2, cD2, cD1 = coeffs # 一個低頻,多個高頻,高頻數 取決於 level print(cA2) # [1.08726236 0.84094862 0.25745065] print(cD2) # [-0.29518976 -0.11764496 0. ] print(cD1) # [ 0.53073221 -0.08142734 0.19354246 -0.39772483 0.05711374] ### 一次 小波分解, level=1 a = data ca = [] # 近似分量 cd = [] # 細節分量 for i in range(2): (a, d) = pywt.dwt(a, 'db1') # 進行2階離散小波變換 ca.append(a) cd.append(d) print(ca) # [array([0.5600799 , 0.97754127, 0.51145292, 0.67782802, 0.1820451 ]), array([1.08726236, 0.84094862, 0.25745065])] ### 取最后一個 近似信號 print(cd) # [array([ 0.53073221, -0.08142734, 0.19354246, -0.39772483, 0.05711374]), array([-0.29518976, -0.11764496, 0. ])]
wavedec 相當於 dwt 的封裝
離散 2D 小波變換
用法 基本 等同於 1D
2D 1階小波變換 dwt2
def dwt2(data, wavelet, mode='symmetric', axes=(-2, -1)): returns (cA, (cH, cV, cD)) : tuple
要注意返回值,分別為低頻分量,水平高頻、垂直高頻、對角線高頻。高頻的值包含在一個tuple中
示例
import pywt import pywt.data # Load image original = pywt.data.camera() # Wavelet transform of image, and plot approximation and details titles = ['Approximation', 'Horizontal detail', 'Vertical detail', 'Diagonal detail'] coeffs2 = pywt.dwt2(original, 'bior1.3') # 2D 離散信號 小波分解 LL, (LH, HL, HH) = coeffs2 fig = plt.figure(figsize=(12, 3)) for i, a in enumerate([LL, LH, HL, HH]): ax = fig.add_subplot(1, 4, i + 1) ax.imshow(a, interpolation="nearest", cmap=plt.cm.gray) ax.set_title(titles[i], fontsize=10) ax.set_xticks([]) ax.set_yticks([]) fig.tight_layout() plt.show()
2D 多階小波變換 wavedec2
print(pywt.waverec2(coeffs, wavelet='db1', level=3))
官網有 level 參數,我的版本沒有,應該是版本問題,暫未解決
信號重構
小波 經常用於 降噪,降完噪后 需要把 信號進行重構,生成無噪聲的信號,1D、2D 用法類似
def waverec(coeffs, wavelet, mode='symmetric', axis=-1)
示例
import numpy as np import pywt import matplotlib.pylab as plt plt.rcParams['font.sans-serif']=['SimHei'] plt.rcParams['axes.unicode_minus']=False data = np.hstack([np.ones((1, 10)), np.ones((1, 50)) * 2])[0] ca, cd2, cd1 = pywt.wavedec(data, 'db1', level=2) plt.subplot(211) plt.title('original') plt.plot(data) out = pywt.waverec([ca, cd2, cd1], 'db1') plt.subplot(212) plt.title('重構信號') plt.plot(out) plt.show()
小波 VS 傅里葉變換
小波變換還是比較復雜的,確切地說 如果想 徹底弄懂,基本不可能,我這里 只重點記錄下 學習心得
1. 傅里葉變換 的 基 只能是 正弦波,如果 原始波形 比較陡峭,需要無窮多的 正弦波 才能逼近 這種陡峭,計算量很大;小波基 則 比較 靈活,甚至可以自定義小波基;
2. 正弦波 會以 同樣的 幅度 在無窮大空間內做 無限震動,能量巨大;而 小波 是一個 很短的波,它的能力比較集中,而且集中在 某一點附近; 如下圖
之所以叫 小波,就是 跟 傅里葉的正弦波 比較起來 很小
3. 小波 擅長 瞬時突變 信號的檢測,傅里葉變換無能為力
小波 應用於 特征提取
代碼
#進行小波變換,提取樣本特征 wp = pywt.WaveletPacket(SingleSampleDataWavelet, wavelet='db3', mode='symmetric', maxlevel=3) #小波包三層分解 #print([node.path for node in wp.get_level(3, 'natural')]) #第3層有8個 #獲取第level層的節點系數 aaa = wp['aaa'].data #第1個節點 aad = wp['aad'].data #第2個節點 ada = wp['ada'].data #第3個節點 add = wp['add'].data #第4個節點 daa = wp['daa'].data #第5個節點 dad = wp['dad'].data #第6個節點 dda = wp['dda'].data #第7個節點 ddd = wp['ddd'].data #第8個節點 #求取節點的范數 ret1 = np.linalg.norm(aaa,ord=None) #第一個節點系數求得的范數/ 矩陣元素平方和開方 ret2 = np.linalg.norm(aad,ord=None) ret3 = np.linalg.norm(ada,ord=None) ret4 = np.linalg.norm(add,ord=None) ret5 = np.linalg.norm(daa,ord=None) ret6 = np.linalg.norm(dad,ord=None) ret7 = np.linalg.norm(dda,ord=None) ret8 = np.linalg.norm(ddd,ord=None) #8個節點組合成特征向量 SingleSampleFeature = [ret1, ret2, ret3, ret4, ret5, ret6, ret7, ret8]
關鍵是 細節信號 的能量 計算,其實就是 系數(類似於特征值大小) 的 歸一化
參考資料:
https://www.cnblogs.com/shuimuqingyang/p/10919918.html 小波變換庫——Pywalvets 學習筆記
https://pywavelets.readthedocs.io/en/latest/ref/index.html PyWavelets 官網
https://github.com/PyWavelets/pywt PyWavelets git上的demo
https://blog.csdn.net/alwaystry/article/details/52756051 用法挺全的
https://zhuanlan.zhihu.com/p/44215123 小波變換完美通俗講解系列之 (一) 【原理就看這篇吧】
https://blog.csdn.net/zds13257177985/article/details/102896041?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase 小波包變換/能量特征提取/結果圖繪制-python代碼