小波降噪与重构例子 python
原理講解
傅里葉變換
關于傅里葉變換的基本概念在此我們就不再贅述了,
下面我們主要將傅里葉變換的不足。即我們知道傅里葉變化可以分析信號的頻譜,那么為什么還要提出小波變換?答案“對非平穩過程,傅里葉變換有局限性”。看如下一個簡單的信號:
做完FFT(傅里葉變換)后,可以在頻譜上看到清晰的四條線,信號包含四個頻率部分。一切沒有問題,但是,如果是非平穩信號呢?
如上圖,最上邊的是頻率始終不變的平穩信號。而下邊兩個則是頻率隨著時間改變的非平穩信號,它們同樣包含和最上信號相同頻率的四個成分。做FFT后,我們發現這三個時域上有巨大差異的信號,頻譜(幅值譜)卻非常一致。尤其是下邊兩個非平穩信號,我們從頻譜上無法區分它們,因為它們包含的四個頻率的信號的成分確實是一樣的,只是出現的先后順序不同。
可見,傅里葉變換處理非平穩信號有先天缺陷。它只能獲取一段信號總體上包含哪些頻率的成分,但是對各成分出現的時刻并無所知。因此,時域相差很大的兩個信號,可能頻譜一樣。
然而平穩信號大多是制造出來的,自然界的大量信號幾乎都是非平穩的。
短時傅里葉變換
一個簡單可行的方法就是——加窗。 “把整個時域過程分解成無數個等長的小過程,每個小過程近似平穩,再傅里葉變換,就知道在哪個時間點上出現了什么頻率了。”這就是短時傅里葉變換。
看圖:
時域上分成一段一段做FFT,不就知道頻率成分隨著時間的變化情況了嗎?
使用STFT存在一個問題,我們應該用多寬的窗函數?
窗太寬太窄都有問題:
小波變換
那么你可能會想到,讓窗口大小變起來,多做幾次STFT不就可以了嗎?!沒錯,小波變換就有著這樣的思路。
但事實上小波并不是這么做的(有人認為“小波變換就是根據算法,加不等長的窗,對每一小部分進行傅里葉變換”,這是不準確的。小波變換并沒有采用窗的思想,更沒有做傅里葉變換。)
至于為什么不采用可變窗的STFT呢,我認為是因為這樣做冗余會太嚴重,STFT做不到正交化,這也是它的一大缺陷。
于是小波變換的出發點和STFT還是不同的。STFT是給信號加窗,分段做FFT;而小波直接把傅里葉變換的基給換了——將無限長的三角函數基換成了有限長的會衰減的小波基。這樣不僅能夠獲取頻率,還可以定位到時間了~
解釋:
來我們回顧一下傅里葉變換吧,沒弄清傅里葉變換為什么能得到信號各個頻率成分的同學也可以再借我的圖理解下。
傅里葉變換把無限長的三角函數作為基函數:
這個基函數會伸縮,平移(其實是兩個正交基的分解)。縮得窄,對應高頻;伸得寬,對應低頻。然后這個基函數不斷和信號做相乘。某一個尺度(寬窄)下乘出來的結果,就可以理解成信號所包含的當前尺度對應頻率成分有多少。于是,基函數會在某些尺度下,與信號相乘得到一個很大的值,因為此時二者有一種重合關系。那么我們就知道信號包含該頻率的成分的多少。
看,這兩種尺度能乘出一個大的值(相關度高),所以信號包含較多的這兩個頻率成分,在頻譜上這兩個頻率會出現兩個峰。
以上,就是粗淺意義上傅里葉變換的原理。
如前邊所說,小波做的改變就在于,將無限長的三角函數基換成了有限長的會衰減的小波基。
從公式可以看出,不同于傅里葉變換,變量只有頻率ω,小波變換有兩個變量:尺度a(scale)和平移量 τ(translation)。尺度a控制小波函數的伸縮,平移量 τ控制小波函數的平移。尺度就對應于頻率(反比),平移量 τ就對應于時間。
當伸縮、平移到這么一種重合情況時,也會相乘得到一個大的值。這時候和傅里葉變換不同的是,這不僅可以知道信號有這樣頻率的成分,而且知道它在時域上存在的具體位置。
而當我們在每個尺度下都平移著和信號乘過一遍后,我們就知道信號在每個位置都包含哪些頻率成分。
原理部分參考文獻
原理部分參考來源
小波變換原理
感謝大佬,感謝大佬。
代碼部分
簡單例子,python版
讀取數據
#小波降噪與重構畫圖
#獲取重構后的趨勢部分和噪聲
def choose(data, w):data=data[:,-1]#只對電價數據進行去噪重構mode = pywt.Modes.smoothw = pywt.Wavelet(w) # 選取小波函數a = dataca = [] # 近似分量cd = [] # 細節分量for i in range(1):#1階變換(a, d) = pywt.dwt(a, w, mode) # 進行1階離散小波變換 dwt為分解ca.append(a)cd.append(d)rec_a = []rec_d = []for i, coeff in enumerate(ca):coeff_list = [coeff, None] +[None] * i#填充長度rec_a.append(pywt.waverec(coeff_list, w)) # waverec重構rec_a=np.array(rec_a[-1])#-1取最后一個基波rec_a=rec_a.reshape(-1,1)for i, coeff in enumerate(cd):coeff_list = [None, coeff] + [None] * irec_d.append(pywt.waverec(coeff_list, w))#取出所有噪聲波,1階變換,有3個噪聲rec_d=np.array(rec_d)return rec_a,rec_d#取出趨勢,噪聲 trainingrec_a, trainingrec_d=choose(txt, 'sym5')#訓練集電價趨勢 和噪聲trainingrec_a為趨勢
trainingrec_d為噪聲
算例2 多階變換 代碼
import numpy as np import matplotlib.pyplot as plt import matplotlib; matplotlib.use('TkAgg') from pylab import * mpl.rcParams['font.sans-serif'] = ['SimHei'] mpl.rcParams['axes.unicode_minus'] = False import pywt #導入小波包#==============生成數據============== X=np.random.uniform(90,100,100) #生成范圍90-100的數,數據100個#============小波繪圖============== def plot_signal_decomp(data, w,title):""":param data: 要進行小波分解重構的數據:param w: 小波基名稱:param title: 繪圖名稱:return: 圖"""mode = pywt.Modes.smoothw = pywt.Wavelet(w) # 選取小波函數a = dataca = [] # 近似分量 ,趨勢cd = [] # 細節分量,噪聲n=3 #定義階數,這里定義3階for i in range(n):#3階(a, d) = pywt.dwt(a, w, mode) # 進行n階離散小波變換ca.append(a)#存放趨勢cd.append(d)#存儲噪聲rec_a = []#存放重構后的趨勢rec_d = []#存放重構后的噪聲for i, coeff in enumerate(ca):coeff_list = [coeff, None] + [None] * irec_a.append(pywt.waverec(coeff_list, w)) # 重構for i, coeff in enumerate(cd):coeff_list = [None, coeff] + [None] * irec_d.append(pywt.waverec(coeff_list, w))print('趨勢個數len(rec_a):',len(rec_a))print('噪聲個數len(rec_d):',len(rec_d))#趨勢只要最后一個,噪聲全要。 加原始數據個數。所以子圖個數=n+1+2fig = plt.figure()for i in range(n+2):if i==n+1:plt.subplot(n+2, 1, i+1)plt.plot(data, label='原數據曲線')plt.legend()elif i==n:plt.subplot(n+2, 1, i+1)plt.plot(rec_a[-1], 'g', label='數據曲線趨勢')plt.legend()else:plt.subplot(n+2, 1, i+1)plt.plot(rec_d[i], 'r', label='數據曲線噪聲%d'%(i+1))plt.legend()plt.show()plot_signal_decomp(X, 'sym5','sym5')#這里選擇sym5小波,小波還有#=======獲取重構后的數據======== def choose(data, w):""":param data: 要進行小波分解重構的數據:param w: 小波基:return: 趨勢 和噪聲"""mode = pywt.Modes.smoothw = pywt.Wavelet(w) # 選取小波函數a = dataca = [] # 近似分量cd = [] # 細節分量n = 3 # 定義階數,這里定義3階for i in range(n): # 3階(a, d) = pywt.dwt(a, w, mode) # 進行n階離散小波變換ca.append(a) # 存放趨勢cd.append(d) # 存儲噪聲rec_a = [] # 存放重構后的趨勢rec_d = [] # 存放重構后的噪聲for i, coeff in enumerate(ca):coeff_list = [coeff, None] + [None] * irec_a.append(pywt.waverec(coeff_list, w)) # 重構for i, coeff in enumerate(cd):coeff_list = [None, coeff] + [None] * irec_d.append(pywt.waverec(coeff_list, w))#返回最后一個趨勢、所有噪聲 return rec_a[-1],rec_dtrainingrec_a, trainingrec_d=choose(X, 'sym5')#所有趨勢 和噪聲 print('趨勢\n',trainingrec_a) print('噪聲1\n',trainingrec_d[0]) print('噪聲2\n',trainingrec_d[1]) print('噪聲3\n',trainingrec_d[2])最后得到的是 趨勢和3部分噪聲。。重構一般是:舍棄一部分噪聲,如(保留2部分噪聲)。重構結果=噪聲1+噪聲2+趨勢。。或者只要趨勢。。 原式數據=噪聲1+噪聲2+噪聲3+趨勢。若不舍棄噪聲,小波分解沒有意義。。
總結
以上是生活随笔為你收集整理的小波降噪与重构例子 python的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cambodia怎么读?
- 下一篇: 电磁吸盘发热是什么原因?