离散小波变换 - 可视化分解细节系数和信号之间的关系

信息处理 Python 小波 重建 分解 可视化
2022-01-13 04:59:58

我试图直接可视化离散小波变换(DWT)细节系数与原始信号/其重建之间的关系。目标是以直观的方式显示它们的关系。我想问一下(请参阅下面的问题):到目前为止,我提出的想法和过程是否正确,如果我是对的,最好在可视化它们的关系之前从原始信号中减去第一级近似值.

最小的例子

这是我解释的最小示例,使用具有 1024 个值Python 的ECG 示例数据作为简单的 1D 信号:pywavelets

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

x = pywt.data.ecg()
plt.plot(x)
plt.legend(['Original signal'])

原始信号

分解是使用Symmlet 5完成的,共有 6 个级别:

w = pywt.Wavelet('sym5')
plt.plot(w.dec_lo)
coeffs = pywt.wavedec(x, w, level=6)

当有意遗漏更高级别的细节系数时,信号的(有损)重建按预期工作(为方便起见,信号绘制在统一的 x 尺度 [0,1] 上):

def reconstruction_plot(yyy, **kwargs):
    """Plot signal vector on x [0,1] independently of amount of values it contains."""
    plt.plot(np.linspace(0, 1, len(yyy)), yyy, **kwargs)

reconstruction_plot(pywt.waverec(coeffs, w)) # full reconstruction 
#reconstruction_plot(pywt.waverec(coeffs[:-1] + [None] * 1, w)) # leaving out detail coefficients up to lvl 5
#reconstruction_plot(pywt.waverec(coeffs[:-2] + [None] * 2, w)) # leaving out detail coefficients up to lvl 4
#reconstruction_plot(pywt.waverec(coeffs[:-3] + [None] * 3, w)) # leaving out detail coefficients up to lvl 3
reconstruction_plot(pywt.waverec(coeffs[:-4] + [None] * 4, w)) # leaving out detail coefficients up to lvl 2
#reconstruction_plot(pywt.waverec(coeffs[:-5] + [None] * 5, w)) # leaving out detail coefficients up to lvl 1
reconstruction_plot(pywt.waverec(coeffs[:-6] + [None] * 6, w)) # leaving out all detail coefficients = reconstruction using lvl1 approximation only
plt.legend(['Full reconstruction', 'Reconstruction using detail coefficients lvl 1+2', 'Reconstruction using lvl 1 approximation only'])

重构信号

上面的 DWT 产生 24 个值的 1 级近似向量、24 个值的 1 级细节系数向量、40 个值的 2 级细节向量、72 个值的第 3 级、135 个值的第 4 级、262 个值的第 5 级和516 个值中的 6 个:

plt.stem(coeffs[1]); plt.legend(['Lvl 1 detail coefficients'])
plt.stem(coeffs[2]); plt.legend(['Lvl 2 detail coefficients'])
plt.stem(coeffs[3]); plt.legend(['Lvl 3 detail coefficients'])
plt.stem(coeffs[4]); plt.legend(['Lvl 4 detail coefficients'])
plt.stem(coeffs[5]); plt.legend(['Lvl 5 detail coefficients'])
plt.stem(coeffs[6]); plt.legend(['Lvl 6 detail coefficients'])

1 级详细系数 2 级详细系数 3 级详细系数 4 级详细系数 5 级详细系数 6 级详细系数

似乎我们在原始信号的尖峰周围看到了清晰的模式(还要注意上图的 y 比例)。

现在我的问题:

  1. 我们可以直接将这些系数与信号联系起来是正确的吗?系数的幅度对应于小波在信号中出现的幅度(y轴),系数的位置对应于时间(x轴)。或者在这两者之间我们需要考虑什么?
  2. 在 DWT 之后,最终的 lvl1 近似值仍然存在。不将细节系数与原始信号的关系可视化,而是将原始信号减去 lvl1 近似值可视化是否有意义?(我知道如果不这样做,我很可能也会看到系数和信号之间的关系,请参见下面的图。只是因为它有意义或没有意义。如果它对 lvl1 细节系数有意义,那么它也可能对要与原始信号减去 lvl2 近似值进行比较的 lvl2 细节系数,对吧?)。一个例子:

    # Reconstruction of signal using just lvl1 approximation
    approx_lvl1 = pywt.waverec(coeffs[:-6] + [None] * 6, w)
    # interpolate to original amount of samples (necessary due to numeric solution of transformation not yielding same amount of values)
    approx_lvl1_interp = np.interp(x=np.arange(0, 1024), xp=np.linspace(0, 1024, len(approx_lvl1)), fp=approx_lvl1)
    x_without_lvl1approx = x - approx_lvl1_interp
    
  3. 我使用的细节系数和信号之间关系的直接可视化只是在 [0,1] 的 x 轴上绘制信号和系数。这在概念上应该是有效的,但我不确定我是否真的需要向边距偏移(例如,向量的第一个和最后一个系数没有位于信号的最开头或结尾):

    def reconstruction_stem(yyy, **kwargs):
        """Plot coefficient vector on x [0,1] independently of amount of values it contains."""
        plt.stem(np.linspace(0, 1, len(yyy)), yyy, **kwargs)
    
    reconstruction_plot(x, color='orange')
    reconstruction_plot(x_without_lvl1approx, color='red')
    reconstruction_stem(coeffs[1])
    plt.legend(['Original signal', 'Original signal - lvl1 approximation', 'Detail coefficients'])
    

细节系数 lvl1 与信号之间的关系 细节系数 lvl2 与信号之间的关系 细节系数 lvl3 与信号之间的关系 细节系数 lvl4 与信号的关系 细节系数 lvl5 与信号的关系 细节系数 lvl6 与信号的关系

对于不直接位于原始数据中峰值位置的强系数是否有直观的解释(例如,在 1 级,最低的(最强的负)在 0.25 左右,以及最高的(最强的正)在 0.75 左右)? 虽然有一个清晰的模式(正滞后+负幅度,负滞后+正幅度),但对我来说似乎有点“遥远”。但这可能有一个很好的解释。

谢谢回答!

2个回答

有必要明确区分每个分解级别的近似系数和细节系数以及相关的细节和近似级别,其中不仅涉及系数,而且分别涉及该级别的逆滤波器

我现在才开始涉足小波,即使是非常基本的问题,例如“如何从可用的小波中进行选择”(可能与实现“足够好”所需的级别数有关),我仍然在苦苦挣扎表示),以及“关于小波去噪的所有喧嚣是什么”,因为我似乎能够使用直接高斯去噪或中值滤波器对我的数据类型获得更好的结果。但我离题了......

我在上面提到的一件事是,您的级别编号似乎与我认为我通常的小波约定不一致。特别是 coeffs[0] 是最后一级的近似幅度,在您的情况下,6 coeffs[1] 是第 6 级的细节幅度 coeffs[2] 是第 5 级的细节幅度 ... coeffs[6] 是级别 1 的细节幅度

因此,您的重建仅来自 5 级和 6 级,而不是图中所示的 1 级和 2 级。

=========

更新:我更多地弄乱了你的代码,我认为你说明系数和信号特征之间相关性的想法是合理的,但并不完美。为了更好地说明这一点,我对您的代码进行了一些修改,请参见下文。请注意,在每个步骤中,我都会将系数重新调整为信号的幅度。这也允许人们谈论阈值的概念。

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

plt.close('all')

def reconstruction_plot(yyy, **kwargs):
    """Plot signal vector on x [0,1] independently of amount of values it contains."""
    #plt.figure()
    #plt.plot(np.linspace(0, 1, len(yyy)), yyy, **kwargs)
    ym = np.median(yyy)
    plt.plot(np.linspace(0, 1., num=len(yyy)), yyy-ym, **kwargs)


def reconstruction_stem(yyy, xmax, **kwargs):
    """Plot coefficient vector on x [0,1] independently of amount of values it contains."""
    ymax = yyy.max()
    plt.stem(np.linspace(0, 1., num=len(yyy)), yyy*(xmax/ymax), **kwargs)


x = pywt.data.ecg()
w = pywt.Wavelet('sym5')
nl = 6
coeffs = pywt.wavedec(x, w, level=nl)


'''
plt.figure()
plt.stem(coeffs[1]); plt.legend(['Lvl 6 detail coefficients'])
plt.figure()
plt.stem(coeffs[2]); plt.legend(['Lvl 5 detail coefficients'])
plt.figure()
plt.stem(coeffs[3]); plt.legend(['Lvl 4 detail coefficients'])
plt.figure()
plt.stem(coeffs[4]); plt.legend(['Lvl 3 detail coefficients'])
plt.figure()
plt.stem(coeffs[5]); plt.legend(['Lvl 2 detail coefficients'])
plt.figure()
plt.stem(coeffs[6]); plt.legend(['Lvl 1 detail coefficients'])
'''


xmax = x.max()
for i in range(nl):
    plt.figure()
    reconstruction_plot(x) # original signal 
    #reconstruction_plot(pywt.waverec(coeffs, w)) # full reconstruction 
    reconstruction_plot(pywt.waverec(coeffs[:i+2] + [None] * (nl-i-1), w)) # partial reconstruction 
    reconstruction_stem(coeffs[i+1], xmax, markerfmt ='none', linefmt='r-')
    #plt.legend(['Original', 'Full reconstruction', ('Rec to lvl %d')%(nl-i), ('Details for lvl %d')%(nl-i)])
    plt.legend(['Original', ('Rec to lvl %d')%(nl-i), ('Details for lvl %d')%(nl-i)])