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'])
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'])
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'])
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:
- É 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?
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
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'])
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!