Transformação discreta de wavelet - visualizando a relação entre coeficientes de detalhe decompostos e sinal

12

Estou tentando visualizar diretamente a relação entre os coeficientes de detalhe da transformada de wavelet discreta (DWT) e o sinal original / sua reconstrução. O objetivo é mostrar sua relação de maneira intuitiva. Eu gostaria de fazer (veja as perguntas abaixo): se a idéia e o processo que eu criei estão corretos até agora, e se eu estiver certo, seria melhor subtrair a aproximação do 1º nível do sinal original antes de visualizar sua relação .

Exemplo mínimo

Aqui está o exemplo mínimo em que baseio minha explicação, usando os dados de exemplo de ECG do Pythonpywavelets , que tem valores 1024, como um sinal 1D simples:

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'])

Sinal original

A decomposição é feita usando um Symmlet 5 com um total de 6 níveis:

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

A reconstrução (com perdas) do sinal funciona como esperado ao deixar intencionalmente coeficientes de detalhe de níveis mais altos (os sinais são plotados em escala x uniforme [0,1] por conveniência):

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'])

Sinal reconstruído

O DWT acima produz um vetor de aproximação de nível 1 de 24 valores, o nível 1 detalha o vetor de coeficiente de 24 valores, o vetor de detalhe de nível 2 de 40 valores, o nível 3 de 72 valores, o nível 4 de 135 valores, o nível 5 de 262 valores e o nível 6 de 516 valores:

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'])

Coeficientes de detalhe de nível 1 Coeficientes de detalhe de nível 2 Coeficientes de detalhe de nível 3 Coeficientes de detalhe de nível 4 Coeficientes de detalhe de nível 5 Coeficientes de detalhe de nível 6

Parece que vemos padrões claros em torno dos picos nos sinais originais (também preste atenção à escala y dos gráficos acima).

Agora às minhas perguntas:

  1. É correto que possamos relacionar diretamente esses coeficientes ao sinal? A amplitude do coeficiente corresponde à amplitude com a qual a wavelet ocorre no sinal (eixo y) e a posição do coeficiente corresponde ao tempo (eixo x). Ou há algo entre o que precisamos considerar?
  2. Após o DWT, a aproximação final do lvl1 permanece. Faz sentido não visualizar a relação dos coeficientes de detalhes com o sinal original, mas com o sinal original menos a aproximação lvl1? (Eu sei que provavelmente também veria a relação entre coeficientes e sinal sem fazer isso, veja, por exemplo, gráficos abaixo. É apenas para isso que faz sentido ou não. Se faz sentido para os coeficientes de detalhe do lvl1, também pode fazer sentido para coeficientes de detalhe lvl2 a serem comparados com o sinal original menos a aproximação lvl2, certo?). Um exemplo:

    # 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. A visualização direta da relação entre os coeficientes de detalhes e o sinal que eu uso apenas plota o sinal e os coeficientes em um eixo x de [0,1]. Conceitualmente, isso deve ser válido, mas não tenho certeza se eu precisaria de um deslocamento em direção às margens (por exemplo, o primeiro e o último coeficiente do vetor não estejam posicionados no início ou no final do sinal):

    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'])
    

Relação entre os coeficientes de detalhe lvl1 e o sinal Relação entre os coeficientes de detalhe lvl2 e o sinal Relação entre os coeficientes de detalhe lvl3 e o sinal Relação entre os coeficientes de detalhe lvl4 e o sinal Relação entre os coeficientes de detalhe lvl5 e o sinal Relação entre os coeficientes de detalhe lvl6 e o ​​sinal

Existe uma explicação intuitiva para os coeficientes fortes que não estão diretamente nas posições dos picos nos dados originais (por exemplo, no nível 1, o mais baixo (mais forte negativo), em torno de 0,25, e o mais alto (mais forte, positivo) em torno de 0,75 )? Embora exista um padrão claro (atraso positivo + amplitude negativa, atraso negativo + amplitude positiva), esses parecem um pouco "distantes" para mim. Mas provavelmente existe uma boa explicação para isso.

Obrigado por responder!

geekoverdose
fonte
Você não recebeu uma resposta, mas sua pergunta em si é um bom tutorial para implementar a análise de wavelet no Python. Obrigado!
Farzad

Respostas:

1

É necessário distinguir claramente entre os coeficientes de aproximação e detalhe em cada nível de decomposição e os níveis associados Detalhes e aproximação que envolvem não apenas os coeficientes, mas também os filtros inversos nesse nível, respectivamente

CD86
fonte
0

Só agora estou começando a me interessar por wavelets, e ainda estou lutando, mesmo com perguntas muito básicas, como "como escolher entre um monte de wavelets disponíveis" (provavelmente tem a ver com o número de níveis que você precisa para alcançar "o suficiente") representação) e "o que há de tão contagioso no denoising com wavelets", porque parece que sou capaz de obter melhores resultados para o meu tipo de dados com denoising gaussiano reto ou filtros medianos. Mas eu discordo ....

Uma coisa que observei acima é que sua numeração de nível parece inconsistente com o que acredito ser as convenções de wavelet usuais. Em particular, coeficientes [0] são as amplitudes de aproximação no último nível; no seu caso, 6 coeficientes [1] é a amplitude de detalhe no nível 6 coeficientes [2] é a amplitude de detalhe no nível 5 ... coeficientes [6] é o amplitude de detalhe no nível 1

Portanto, suas reconstruções são apenas do nível 5 e 6, não do nível 1 e 2, conforme indicado em suas parcelas.

=========

Atualização: mexi mais com seu código e acho que sua ideia de ilustrar a correlação entre coeficientes e recursos de sinal é sólida, mas não perfeita. Eu me diverti um pouco com seu código para ilustrar melhor isso, veja abaixo. Observe que em cada etapa eu redimensiono os coeficientes para a magnitude do sinal. Isso permite falar sobre o conceito de limiar também.

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)])
user40719
fonte