小波变换简介

本文链接个人站 | 简书 | CSDN
版权声明:除特别声明外,本博客文章均采用 BY-NC-SA 许可协议。转载请注明出处。

1. 傅里叶变换的局限性

傅里叶变换只能得到一个信号包含哪些频率成分,但无法从频域上得知信号在不同时间的频率信息,因此对频率会随着时间而改变的信号是无能为力的。举例来说:

import numpy as np
import matplotlib.pyplot as plt
from scipy.fftpack import fft

t = np.linspace(0, 1, 400, endpoint=False)
cond = [t<0.25, (t>=0.25)&(t<0.5), t>=0.5]
f1 = lambda t: np.cos(2*np.pi*10*t)
f2 = lambda t: np.cos(2*np.pi*50*t)
f3 = lambda t: np.cos(2*np.pi*100*t)

y1 = np.piecewise(t, cond, [f1, f2, f3])
y2 = np.piecewise(t, cond, [f2, f1, f3])

Y1 = abs(fft(y1))
Y2 = abs(fft(y2))

plt.figure(figsize=(12, 9))
plt.subplot(221)
plt.plot(t, y1)
plt.title('signal_1 in time domain')
plt.xlabel('Time/second')

plt.subplot(222)
plt.plot(range(400), Y1)
plt.title('signal_1 in frequency domain')
plt.xlabel('Frequency/Hz')

plt.subplot(223)
plt.plot(t, y2)
plt.title('signal_2 in time domain')
plt.xlabel('Time/second')

plt.subplot(224)
plt.plot(range(400), Y2)
plt.title('signal_2 in frequency domain')
plt.xlabel('Frequency/Hz')

plt.tight_layout()
plt.show()
图1. 傅里叶变换无法应对频率随时间变化的信号

从时域上看相差很大的两个信号,在频域上却非常相近。无法从傅里叶变换得到的频域里得知某个频率是在哪个时间出现的。

一个很自然的思路是加窗,将长时间信号分成数个较短的等长信号,然后再分别对每个窗进行傅里叶变换,从而得到频率随时间的变化,这就是所谓的短时距傅里叶变换。这个做法的缺陷在于,窗函数越宽,频率的分辨率越好,但时间分辨率越差;反之,当窗函数越窄,时间的分辨率越好,但频率分辨率越差。

2. 连续小波变换

小波变换则可以解决这个问题。图2是对图1中的两个信号分别进行小波变换得到的时频关系。从图中不仅可以看到信号中有哪些频率,还可以看到不同的频率成分在什么时间出现。

图2. 小波变换能给出时频关系

小波函数定义为
\psi_{a,b}(t) = \frac{1}{\sqrt a}\psi\left(\frac{t-b}{a}\right)
其中 a 是缩放因子,控制小波函数的伸缩;b 是平移参数,控制小波函数的平移。缩放因子对应频率,平移参数对应时间。

f(t) 在缩放因子为 a 的子空间的投影为
f_a(t) = \int_{-\infty}^{+\infty}W_f(a,b)\psi_{a,b}^*(t)\mathrm db
其中小波系数为
W_f(a, b) = \int_{-\infty}^{+\infty}f(t)\psi_{a,b}^*(t)\mathrm dt
^* 代表复共轭。

为了更直观地理解小波变换,先引入 Parseval 定理:

f(t)g(t) 都是平方可积函数,则
\int_{-\infty}^{+\infty} f(t)g^*(t)\mathrm dt = \frac1{2\pi}\int_{-\infty}^{+\infty}F(\omega)G^*(\omega)\mathrm d\omega
其中 F(\omega)=\mathcal F[f(t)]G(\omega)=\mathcal F[g(t)]

证明如下:
\begin{split} \int_{-\infty}^{+\infty}f(t)g^*(t)\mathrm dt &=\int_{-\infty}^{+\infty}\left[\frac1{2\pi}\int_{-\infty}^{+\infty}F(\omega)\mathrm e^{i\omega t}\mathrm d\omega\right]g^*(t)\mathrm dt\\ &=\frac1{2\pi}\int_{-\infty}^{+\infty}F(\omega)\left[\int_{-\infty}^{+\infty}g^*(t)\mathrm e^{i\omega t}\mathrm dt\right]\mathrm d\omega\\ &=\frac1{2\pi}\int_{-\infty}^{+\infty}F(\omega)\left[\int_{-\infty}^{+\infty}g(t)\mathrm e^{-i\omega t}\mathrm dt\right]^*\mathrm d\omega\\ &= \frac1{2\pi}\int_{-\infty}^{+\infty}F(\omega)G^*(\omega)\mathrm d\omega \end{split}
f(t) 是信号,g(t)=\psi_{a,b}(t) 是小波函数,则小波变换
W_f(a,b) = \int_{-\infty}^{+\infty}f(t)\psi^*_{a,b}(t)\mathrm dt=\frac1{2\pi}\int_{-\infty}^{+\infty}F(\omega)\Psi^*_{a,b}(\omega)\mathrm d\omega
从上式不难看出,只有当小波中心频率与原始信号固有频率接近的时候,小波系数才会取得极大值。因此,小波可以看作是一个只允许频率和小波中心频率相近的信号通过的带通滤波器。通过缩放因子可以得到一系列不同的中心频率,通过平移系数则可以检测时域上不同位置的信号。这样就得到了原信号在各个时间点包含的频率信息。

在 Python 中可以使用 pywt.cwt 实现连续小波变换。图2的结果就是由下面这段代码产生的。

import numpy as np
import matplotlib.pyplot as plt
import pywt

t = np.linspace(0, 1, 400, endpoint=False)
cond = [t<0.25, (t>=0.25)&(t<0.5), t>=0.5]
f1 = lambda t: np.cos(2*np.pi*10*t)
f2 = lambda t: np.cos(2*np.pi*50*t)
f3 = lambda t: np.cos(2*np.pi*100*t)

y1 = np.piecewise(t, cond, [f1, f2, f3])
y2 = np.piecewise(t, cond, [f2, f1, f3])

cwtmatr1, freqs1 = pywt.cwt(y1, np.arange(1, 200), 'cgau8', 1/400)
cwtmatr2, freqs2 = pywt.cwt(y2, np.arange(1, 200), 'cgau8', 1/400)

plt.figure(figsize=(12, 9))
plt.subplot(221)
plt.plot(t, y1)
plt.title('signal_1 in time domain')
plt.xlabel('Time/second')

plt.subplot(222)
plt.contourf(t, freqs1, abs(cwtmatr1))
plt.title('time-frequency relationship of signal_1')
plt.xlabel('Time/second')
plt.ylabel('Frequency/Hz')

plt.subplot(223)
plt.plot(t, y2)
plt.title('signal_2 in time domain')
plt.xlabel('Time/second')

plt.subplot(224)
plt.contourf(t, freqs2, abs(cwtmatr2))
plt.title('time-frequency relationship of signal_2')
plt.xlabel('Time/second')
plt.ylabel('Frequency/Hz')

plt.tight_layout()
plt.show()

3. 离散小波变换

离散小波变换顾名思义就是离散的输入以及离散的输出,但是这里并没有一个简单而明确的公式来表示输入及输出的关系,只能以阶层式架构来表示。

Python 中可以使用 pywt.dwt实现离散小波变换:

import numpy as np
import matplotlib.pyplot as plt
import pywt

y = pywt.data.ecg()
x = range(len(y))

ca, cd = pywt.dwt(y, 'db4')
ya = pywt.idwt(ca, None, 'db4') # approximated component
yd = pywt.idwt(None, cd, 'db4') # detailed component

plt.figure(figsize=(12,9))
plt.subplot(311)
plt.plot(x, y)
plt.title('original signal')
plt.subplot(312)
plt.plot(x, ya)
plt.title('approximated component')
plt.subplot(313)
plt.plot(x, yd)
plt.title('detailed component')
plt.tight_layout()
plt.show()

上面的代码将原信号分解为一个低频的近似分量和一个高频的细节分量:


图3. 利用 pywt.dwt 将原信号分解为近似分量和细节分量

也可以使用 pywt.wavedec 直接进行多阶小波分解:

import numpy as np
import matplotlib.pyplot as plt
import pywt

y = pywt.data.ecg()
x = range(len(y))

coeffs = pywt.wavedec(y, 'db4', level=4) # 4阶小波分解

ya4 = pywt.waverec(np.multiply(coeffs, [1, 0, 0, 0, 0]).tolist(), 'db4')
yd4 = pywt.waverec(np.multiply(coeffs, [0, 1, 0, 0, 0]).tolist(), 'db4')
yd3 = pywt.waverec(np.multiply(coeffs, [0, 0, 1, 0, 0]).tolist(), 'db4')
yd2 = pywt.waverec(np.multiply(coeffs, [0, 0, 0, 1, 0]).tolist(), 'db4')
yd1 = pywt.waverec(np.multiply(coeffs, [0, 0, 0, 0, 1]).tolist(), 'db4')

plt.figure(figsize=(12, 12))
plt.subplot(611)
plt.plot(x, y)
plt.title('original signal')
plt.subplot(612)
plt.plot(x, ya4)
plt.title('approximated component in level 4')
plt.subplot(613)
plt.plot(x, yd4)
plt.title('detailed component in level 4')
plt.subplot(614)
plt.plot(x, yd3)
plt.title('detailed component in level 3')
plt.subplot(615)
plt.plot(x, yd2)
plt.title('detailed component in level 2')
plt.subplot(616)
plt.plot(x, yd1)
plt.title('detailed component in level 1')
plt.tight_layout()
plt.show()

上面的代码将原信号分解为一个低频的近似分量和四个高频的细节分量:


图4. 利用 pywt.wavedec 将原信号进行多阶小波分解

参考文献

  1. 小波与傅里叶分析基础(第二版), 电子工业出版社,2017.6
  2. Wavelet - Wikipedia https://en.wikipedia.org/wiki/Wavelet
  3. 知乎专栏 - 时频分析与小波变换 https://zhuanlan.zhihu.com/c_123849464
  4. PyWavelets - Wavelet Transforms in Python https://pywavelets.readthedocs.io/en/latest/
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,978评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,954评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,623评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,324评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,390评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,741评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,892评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,655评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,104评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,569评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,254评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,834评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,725评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,950评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,260评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,446评论 2 348

推荐阅读更多精彩内容

  • 一、傅立叶变换的由来 关于傅立叶变换,无论是书本还是在网上可以很容易找到关于傅立叶变换的描述,但是大都是些故弄玄虚...
    constant007阅读 4,415评论 1 10
  • 深入理解傅里叶变换Mar 12, 2017 这原本是我在知乎上对傅立叶变换、拉普拉斯变换、Z变换的联系?为什么要进...
    价值趋势技术派阅读 5,739评论 2 2
  • 1. 傅立叶变换: (1) 傅立叶级数:法国数学家傅里叶发现,任何周期函数都可以用正弦函数和余弦函数构成的无穷级数...
    阿阿阿阿毛阅读 1,596评论 0 2
  • 一、转载自如何直观形象、生动有趣地给文科学生介绍傅里叶变换? 从数学的角度,提供一个形象有趣的解释。理解傅里叶变换...
    合肥黑阅读 1,699评论 0 2
  • 一、学习与实践 1.付出不亚于任何人的努力 2.要谦虚,不要骄傲 3.要每天反省 4.活着,就要感谢 5.积善行,...
    Lucien光阅读 169评论 0 0