admin管理员组

文章数量:1030654

时序顶会基础创新知识点

前面的文章我们总结了傅立叶变换在时间序列中的应用,但FFT实际有其局限性,所以最近陆续在学习小波变换,感觉小波变换要比傅立叶变换更加复杂,所以预计本篇文章会冗长一些。此外,文章不少代码参考了网络博客,因为博客质量良莠不齐,且不少内容是互相转载,从繁多内容中找到有价值的部分,我花了不少时间。我希望能讲清楚小波变换,此外尽量把参考源写清楚。

1. 小波变换与傅立叶变换的差异比较

之前我们一起学习总结过傅立叶变换在时序问题中的应用,那么有了小波变换和傅里叶变换和傅立叶变换有什么区别呢?或者说,为什么有了傅立叶变换还不够,还要有小波变换呢?这是文本要解释的第一个问题。

1.1 傅里叶变换

首先回顾一下傅立叶变换,傅里叶变换是一种频域分析方法,它基于傅里叶级数的思想,将信号表示为一系列不同频率的正弦和余弦函数的线性组合傅里叶变换将信号从时域转换到频域(时域信息完全丢失),得到信号的频谱,频谱反映了信号中不同频率成分的幅度和相位信息。但是有时候,我们希望知道时间序列在不同时刻的频域信息,这时候傅立叶变换就行不通了。此外,如果是下面的情况,频率成分相同,但是时间位置不同,傅立叶变换也是识别不出来了的。这就是FFT的不足。

看下图,三条时间序由三个不同频率的三角函数拼接而成,且很明显它们的先后顺序存在差异。

注:图片来源于网络

但是如果我们做傅立叶变换,会得到如下结果。我们发现明明是三条不同的序列,却得到了同样的频率分析图。这就是傅立叶变换的不足之处,失去了时间维度信息。那么有没有一种可能,能够同时得到时间和频率两个维度的特征分析结果呢,是可以的,这就是小波变换。

1.2 小波变换

而我们今天学习的小波变换也是一种时频分析方法,它通过一组小波基函数对信号进行分解。得到不同尺度和位置的近似系数和细节系数,这些系数反映了信号在不同时间和频率上的局部特征。所以小波变换的结果实际上反映了两个维度:时间和频率,小波变换更适合处理非平稳信号,通过不同尺度的小波函数来捕捉信号在不同时间和频率上的变化,也能够有效地提取信号中的突变、瞬态和局部特征。

对比一下小波变换和傅立叶变换的特性差异,我们可以发现:

注:图片来源于网络

  • 小波变换:具有良好的时频局部性,能够同时在时间和频率上对信号进行局部分析。支持多分辨率分析,通过多级分解可以在不同尺度下观察信号的特征。不同尺度的小波基函数可以捕捉信号在不同时间和频率上的变化,因此非常适合处理非平稳信号,例如包含突变、瞬态等特征的信号。
  • 傅里叶变换:缺乏时频局部性,它只能提供信号的整体频率信息,无法确定某个频率成分在时间上的具体位置。对于非平稳信号,傅里叶变换的结果可能无法准确反映信号的时变特性。不具备多分辨率分析的能力,它只能提供单一分辨率的频域信息。

2. 小波变换的Python实现

我在查博客的时候,看到有些代码用pywt.dwt,有些用pywt.wavedec,还有一些用pywt.cwt,专门查了一下,三者的区别具体如下:

  • pywt.dwt:执行一级离散小波变换(Discrete Wavelet Transform)。它将输入信号分解为两个部分,即近似系数(Approximation coefficients,低频部分,反映信号的总体趋势)和细节系数(Detail coefficients,高频部分,反映信号的局部变化)。
  • pywt.wavedec:执行多级离散小波变换。它会对信号进行多次分解,每一级都将上一级得到的近似系数进一步分解为新的近似系数和细节系数,最终得到不同尺度下的近似系数和各级细节系数。
  • pywt.cwt:执行连续小波变换。输入包括信号signal、尺度scale、小波基等。输出 coefficients 是一个二维复数矩阵,其行对应不同尺度(scales),列对应时间点,幅度 np.abs(coefficients) 反映信号在各尺度和时间点的能量强度,相位 np.angle(coefficients)提供局部相位信息;frequencies 表示各尺度对应的实际频率(Hz),尺度越小频率越高。

2.1 使用pywt.dwt进行一级分解

代码语言:javascript代码运行次数:0运行复制
# 生成信号变量
t = np.linspace(0, 1, num=1000)
signal = np.sin(2 * np.pi * 10 * t) + np.sin(2 * np.pi * 20 * t) + np.sin(3 * np.pi * 30 * t)
# 添加随机噪声
noise = np.random.normal(0, 0.05, len(signal))
signal = signal + noise
# 进行DWT
coeffs = pywt.dwt(signal, 'db1')
cA, cD = coeffs

解释一下几行核心代码,其中'db1' 是小波基的名称,db1 也就是哈尔(Haar)小波,它是最简单且最早被提出的小波基,具有正交性和紧支撑性。pywt.dwt函数会返回一个包含两个元素的元组,这两个元素分别是近似系数(Approximation coefficients)和细节系数(Detail coefficients),并将其赋值给变量 coeffs。

近似系数:代表信号的低频部分,体现了信号的总体趋势和缓慢变化的特征。可以把它看作是对原始信号进行平滑处理后的结果,保留了信号的主要信息。例如在图像中,低频部分对应着图像的整体亮度和大致轮廓;在音频信号里,低频部分对应着声音的基频和主要音调。

细节系数:代表信号的高频部分,反映了信号的局部变化、细节特征以及噪声等信息。它体现了信号在不同尺度下的快速变化情况。在图像中,高频部分对应着图像的边缘、纹理等细节信息;在音频信号中,高频部分对应着声音的音色、谐波等细节。

cA, cD = coeffs 这行代码将 coeffs 元组中的两个元素分别赋值给变量 cA 和 cD。cA 是近似系数,cD 代表细节系数。下面是绘制出的分解结果:

代码语言:javascript代码运行次数:0运行复制
# 绘制原始信号及其DWT系数
plt.figure(figsize=(12, 6))
plt.subplot(3, 1, 1)
plt.plot(t, signal, label='Original Signal')
plt.legend()
plt.subplot(3, 1, 2)
plt.plot(cA, label='Approximation Coefficients')
plt.legend()
plt.subplot(3, 1, 3)
plt.plot(cD, label='Detail Coefficients')
plt.legend()
plt.tight_layout()
plt.show()

2.2 使用pywt.wave进行多级分解

代码语言:javascript代码运行次数:0运行复制
# .html
import numpy as np
import pywt
import matplotlib.pyplot as plt
# 生成信号变量
t = np.linspace(0, 1, num=1000)
signal = np.sin(2 * np.pi * 10 * t) + np.sin(2 * np.pi * 20 * t) + np.sin(3 * np.pi * 30 * t)
# 添加随机噪声
noise = np.random.normal(0, 0.05, len(signal))
signal = signal + noise
wavelet_name = 'db4'  # 定义小波基名称为'db4'
# 小波变换
coeffs = pywt.wavedec(signal, wavelet_name, level=4)  # 使用指定小波基进行4级小波分解
代码语言:javascript代码运行次数:0运行复制

这里我们用了'db4' ,代表的是四阶 Daubechies 小波基,也是一类常用的小波基,具有紧支撑性和正交性等特性。

代码coeffs = pywt.wavedec(signal, wavelet_name, level=4)实现了多级离散小波变换,signal 是输入的一维信号,wavelet_name 是指定的小波基名称,这里使用的是 'db4'。

level=4 指定了小波变换的分解级数为 4。多级离散小波变换会对信号进行多次分解,每一级都将上一级得到的近似系数进一步分解为新的近似系数和细节系数。本代码进行了四级分解,返回一个列表 coeffs,列表的第一个元素是最高级别的近似系数(经过四级分解后得到的最粗略的近似),其余元素依次是从第一级到第四级的细节系数。

代码语言:javascript代码运行次数:0运行复制
# 绘制原始信号图像
plt.figure(figsize=(8, 6))
plt.subplot(5, 1, 1)
plt.plot(t, signal)
plt.title('Original Signal')
plt.xlabel('Time')
plt.ylabel('Amplitude')
# 绘制小波分解信号图像
for i in range(1, len(coeffs)):
    plt.subplot(5, 1, i+1)
    plt.plot(t[:len(coeffs[i])], coeffs[i])
    plt.title(f'Wavelet Coefficients - Level {i}')
    plt.xlabel('Time')
    plt.ylabel('Amplitude')
plt.tight_layout()
plt.show()

这里大家也可以尝试使用pywt.wave进行一级分解,比较两者的结果是否相同。

2.3 使用pywt.cwt进行连续小波变换

代码语言:javascript代码运行次数:0运行复制
import numpy as np
import matplotlib.pyplot as plt
import pywt
from pywt import scale2frequency
# 生成合成信号
fs = 1000  # 采样频率 (Hz)
t = np.linspace(0, 1, fs, endpoint=False)  # 时间轴 (1秒)
f1, f2 = 10, 50  # 两个频率成分
signal = np.sin(2 * np.pi * f1 * t) + np.sin(2 * np.pi * f2 * t)  # 合成信号
# 添加高斯噪声
noise = 0.5 * np.random.randn(len(t))
signal_noisy = signal + noise
# 定义CWT参数
wavelet = 'morl'  # Morlet小波
scales = np.arange(1, 128)  # 尺度范围(与频率成反比)

合成一个包含10Hz和50Hz正弦波的信号,并添加噪声模拟真实数据。选择Morlet小波,根据目标频率调整尺度scales范围,尺度越小对应频率越高。

代码语言:javascript代码运行次数:0运行复制
# 计算CWT
coefficients, frequencies = pywt.cwt(signal_noisy, scales, wavelet, sampling_period=1/fs)
# 获取实际频率(PyWavelets的scale2frequency需注意单位)
frequencies = scale2frequency(wavelet, scales) * fs  # 转换为实际频率(Hz)

进行变换,并使用scale2frequency将尺度转换为实际频率。最后进行可视化,时频图用imshow展示CWT系数的绝对值(能量分布)。等高线图更精确显示频率随时间的变化。

这样,通过本篇文章我们就知道了小波变换与傅立叶变换的区别,小波变换的优势,同时我们还总结小波变换的三个常用代码。但是,时间序列问题中具体如何应用小波变换?小波变换能带来哪些不一样的性能提升,这个我们留到下篇讲解。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-04-14,如有侵权请联系 cloudcommunity@tencent 删除函数基础网络变量博客

时序顶会基础创新知识点

前面的文章我们总结了傅立叶变换在时间序列中的应用,但FFT实际有其局限性,所以最近陆续在学习小波变换,感觉小波变换要比傅立叶变换更加复杂,所以预计本篇文章会冗长一些。此外,文章不少代码参考了网络博客,因为博客质量良莠不齐,且不少内容是互相转载,从繁多内容中找到有价值的部分,我花了不少时间。我希望能讲清楚小波变换,此外尽量把参考源写清楚。

1. 小波变换与傅立叶变换的差异比较

之前我们一起学习总结过傅立叶变换在时序问题中的应用,那么有了小波变换和傅里叶变换和傅立叶变换有什么区别呢?或者说,为什么有了傅立叶变换还不够,还要有小波变换呢?这是文本要解释的第一个问题。

1.1 傅里叶变换

首先回顾一下傅立叶变换,傅里叶变换是一种频域分析方法,它基于傅里叶级数的思想,将信号表示为一系列不同频率的正弦和余弦函数的线性组合傅里叶变换将信号从时域转换到频域(时域信息完全丢失),得到信号的频谱,频谱反映了信号中不同频率成分的幅度和相位信息。但是有时候,我们希望知道时间序列在不同时刻的频域信息,这时候傅立叶变换就行不通了。此外,如果是下面的情况,频率成分相同,但是时间位置不同,傅立叶变换也是识别不出来了的。这就是FFT的不足。

看下图,三条时间序由三个不同频率的三角函数拼接而成,且很明显它们的先后顺序存在差异。

注:图片来源于网络

但是如果我们做傅立叶变换,会得到如下结果。我们发现明明是三条不同的序列,却得到了同样的频率分析图。这就是傅立叶变换的不足之处,失去了时间维度信息。那么有没有一种可能,能够同时得到时间和频率两个维度的特征分析结果呢,是可以的,这就是小波变换。

1.2 小波变换

而我们今天学习的小波变换也是一种时频分析方法,它通过一组小波基函数对信号进行分解。得到不同尺度和位置的近似系数和细节系数,这些系数反映了信号在不同时间和频率上的局部特征。所以小波变换的结果实际上反映了两个维度:时间和频率,小波变换更适合处理非平稳信号,通过不同尺度的小波函数来捕捉信号在不同时间和频率上的变化,也能够有效地提取信号中的突变、瞬态和局部特征。

对比一下小波变换和傅立叶变换的特性差异,我们可以发现:

注:图片来源于网络

  • 小波变换:具有良好的时频局部性,能够同时在时间和频率上对信号进行局部分析。支持多分辨率分析,通过多级分解可以在不同尺度下观察信号的特征。不同尺度的小波基函数可以捕捉信号在不同时间和频率上的变化,因此非常适合处理非平稳信号,例如包含突变、瞬态等特征的信号。
  • 傅里叶变换:缺乏时频局部性,它只能提供信号的整体频率信息,无法确定某个频率成分在时间上的具体位置。对于非平稳信号,傅里叶变换的结果可能无法准确反映信号的时变特性。不具备多分辨率分析的能力,它只能提供单一分辨率的频域信息。

2. 小波变换的Python实现

我在查博客的时候,看到有些代码用pywt.dwt,有些用pywt.wavedec,还有一些用pywt.cwt,专门查了一下,三者的区别具体如下:

  • pywt.dwt:执行一级离散小波变换(Discrete Wavelet Transform)。它将输入信号分解为两个部分,即近似系数(Approximation coefficients,低频部分,反映信号的总体趋势)和细节系数(Detail coefficients,高频部分,反映信号的局部变化)。
  • pywt.wavedec:执行多级离散小波变换。它会对信号进行多次分解,每一级都将上一级得到的近似系数进一步分解为新的近似系数和细节系数,最终得到不同尺度下的近似系数和各级细节系数。
  • pywt.cwt:执行连续小波变换。输入包括信号signal、尺度scale、小波基等。输出 coefficients 是一个二维复数矩阵,其行对应不同尺度(scales),列对应时间点,幅度 np.abs(coefficients) 反映信号在各尺度和时间点的能量强度,相位 np.angle(coefficients)提供局部相位信息;frequencies 表示各尺度对应的实际频率(Hz),尺度越小频率越高。

2.1 使用pywt.dwt进行一级分解

代码语言:javascript代码运行次数:0运行复制
# 生成信号变量
t = np.linspace(0, 1, num=1000)
signal = np.sin(2 * np.pi * 10 * t) + np.sin(2 * np.pi * 20 * t) + np.sin(3 * np.pi * 30 * t)
# 添加随机噪声
noise = np.random.normal(0, 0.05, len(signal))
signal = signal + noise
# 进行DWT
coeffs = pywt.dwt(signal, 'db1')
cA, cD = coeffs

解释一下几行核心代码,其中'db1' 是小波基的名称,db1 也就是哈尔(Haar)小波,它是最简单且最早被提出的小波基,具有正交性和紧支撑性。pywt.dwt函数会返回一个包含两个元素的元组,这两个元素分别是近似系数(Approximation coefficients)和细节系数(Detail coefficients),并将其赋值给变量 coeffs。

近似系数:代表信号的低频部分,体现了信号的总体趋势和缓慢变化的特征。可以把它看作是对原始信号进行平滑处理后的结果,保留了信号的主要信息。例如在图像中,低频部分对应着图像的整体亮度和大致轮廓;在音频信号里,低频部分对应着声音的基频和主要音调。

细节系数:代表信号的高频部分,反映了信号的局部变化、细节特征以及噪声等信息。它体现了信号在不同尺度下的快速变化情况。在图像中,高频部分对应着图像的边缘、纹理等细节信息;在音频信号中,高频部分对应着声音的音色、谐波等细节。

cA, cD = coeffs 这行代码将 coeffs 元组中的两个元素分别赋值给变量 cA 和 cD。cA 是近似系数,cD 代表细节系数。下面是绘制出的分解结果:

代码语言:javascript代码运行次数:0运行复制
# 绘制原始信号及其DWT系数
plt.figure(figsize=(12, 6))
plt.subplot(3, 1, 1)
plt.plot(t, signal, label='Original Signal')
plt.legend()
plt.subplot(3, 1, 2)
plt.plot(cA, label='Approximation Coefficients')
plt.legend()
plt.subplot(3, 1, 3)
plt.plot(cD, label='Detail Coefficients')
plt.legend()
plt.tight_layout()
plt.show()

2.2 使用pywt.wave进行多级分解

代码语言:javascript代码运行次数:0运行复制
# .html
import numpy as np
import pywt
import matplotlib.pyplot as plt
# 生成信号变量
t = np.linspace(0, 1, num=1000)
signal = np.sin(2 * np.pi * 10 * t) + np.sin(2 * np.pi * 20 * t) + np.sin(3 * np.pi * 30 * t)
# 添加随机噪声
noise = np.random.normal(0, 0.05, len(signal))
signal = signal + noise
wavelet_name = 'db4'  # 定义小波基名称为'db4'
# 小波变换
coeffs = pywt.wavedec(signal, wavelet_name, level=4)  # 使用指定小波基进行4级小波分解
代码语言:javascript代码运行次数:0运行复制

这里我们用了'db4' ,代表的是四阶 Daubechies 小波基,也是一类常用的小波基,具有紧支撑性和正交性等特性。

代码coeffs = pywt.wavedec(signal, wavelet_name, level=4)实现了多级离散小波变换,signal 是输入的一维信号,wavelet_name 是指定的小波基名称,这里使用的是 'db4'。

level=4 指定了小波变换的分解级数为 4。多级离散小波变换会对信号进行多次分解,每一级都将上一级得到的近似系数进一步分解为新的近似系数和细节系数。本代码进行了四级分解,返回一个列表 coeffs,列表的第一个元素是最高级别的近似系数(经过四级分解后得到的最粗略的近似),其余元素依次是从第一级到第四级的细节系数。

代码语言:javascript代码运行次数:0运行复制
# 绘制原始信号图像
plt.figure(figsize=(8, 6))
plt.subplot(5, 1, 1)
plt.plot(t, signal)
plt.title('Original Signal')
plt.xlabel('Time')
plt.ylabel('Amplitude')
# 绘制小波分解信号图像
for i in range(1, len(coeffs)):
    plt.subplot(5, 1, i+1)
    plt.plot(t[:len(coeffs[i])], coeffs[i])
    plt.title(f'Wavelet Coefficients - Level {i}')
    plt.xlabel('Time')
    plt.ylabel('Amplitude')
plt.tight_layout()
plt.show()

这里大家也可以尝试使用pywt.wave进行一级分解,比较两者的结果是否相同。

2.3 使用pywt.cwt进行连续小波变换

代码语言:javascript代码运行次数:0运行复制
import numpy as np
import matplotlib.pyplot as plt
import pywt
from pywt import scale2frequency
# 生成合成信号
fs = 1000  # 采样频率 (Hz)
t = np.linspace(0, 1, fs, endpoint=False)  # 时间轴 (1秒)
f1, f2 = 10, 50  # 两个频率成分
signal = np.sin(2 * np.pi * f1 * t) + np.sin(2 * np.pi * f2 * t)  # 合成信号
# 添加高斯噪声
noise = 0.5 * np.random.randn(len(t))
signal_noisy = signal + noise
# 定义CWT参数
wavelet = 'morl'  # Morlet小波
scales = np.arange(1, 128)  # 尺度范围(与频率成反比)

合成一个包含10Hz和50Hz正弦波的信号,并添加噪声模拟真实数据。选择Morlet小波,根据目标频率调整尺度scales范围,尺度越小对应频率越高。

代码语言:javascript代码运行次数:0运行复制
# 计算CWT
coefficients, frequencies = pywt.cwt(signal_noisy, scales, wavelet, sampling_period=1/fs)
# 获取实际频率(PyWavelets的scale2frequency需注意单位)
frequencies = scale2frequency(wavelet, scales) * fs  # 转换为实际频率(Hz)

进行变换,并使用scale2frequency将尺度转换为实际频率。最后进行可视化,时频图用imshow展示CWT系数的绝对值(能量分布)。等高线图更精确显示频率随时间的变化。

这样,通过本篇文章我们就知道了小波变换与傅立叶变换的区别,小波变换的优势,同时我们还总结小波变换的三个常用代码。但是,时间序列问题中具体如何应用小波变换?小波变换能带来哪些不一样的性能提升,这个我们留到下篇讲解。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。原始发表:2025-04-14,如有侵权请联系 cloudcommunity@tencent 删除函数基础网络变量博客

本文标签: 时序顶会基础创新知识点