Trasformata wavelet discreta: visualizzazione del rapporto tra coefficienti di dettaglio decomposti e segnale


12

Sto cercando di visualizzare direttamente la relazione tra i coefficienti di dettaglio della trasformata wavelet discreta (DWT) e il segnale originale / la sua ricostruzione. L'obiettivo è mostrare la loro relazione in modo intuitivo. Vorrei porre (vedi le domande seguenti): se l'idea e il processo che ho escogitato sono corretti finora, e se ho ragione, potrebbe essere meglio sottrarre l'approssimazione di 1 ° livello dal segnale originale prima di visualizzare la loro relazione .

Esempio minimo

Ecco l'esempio minimo su cui baso la mia spiegazione, usando i dati di esempio ECG di Pythonpywavelets , che ha 1024 valori, come un semplice segnale 1D:

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

Segnale originale

La decomposizione viene eseguita utilizzando un Symmlet 5 con un totale di 6 livelli:

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

La ricostruzione (con perdita) del segnale funziona come previsto quando si omettono intenzionalmente coefficienti di dettaglio di livello superiore (i segnali sono tracciati su scala x uniforme [0,1] per comodità):

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

Segnale ricostruito

Il DWT sopra fornisce un vettore di approssimazione di livello 1 di 24 valori, vettore di coefficienti di dettaglio di livello 1 di 24 valori, vettore di dettaglio di livello 2 di 40 valori, livello 3 di 72 valori, livello 4 di 135 valori, livello 5 di 262 valori e livello 6 di 516 valori:

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

Coefficienti di dettaglio di livello 1 Coefficienti di dettaglio di livello 2 Coefficienti di dettaglio di livello 3 Coefficienti di dettaglio di livello 4 Coefficienti di dettaglio di livello 5 Coefficienti di dettaglio di livello 6

Sembra che vediamo segnali chiari attorno ai picchi nei segnali originali (anche prestare attenzione alla scala y dei grafici sopra).

Ora alle mie domande:

  1. È corretto che possiamo collegare direttamente tali coefficienti al segnale? L'ampiezza del coefficiente corrisponde all'ampiezza con cui si verifica la wavelet nel segnale (asse y) e la posizione del coefficiente corrisponde al tempo (asse x). O c'è qualcosa nel mezzo che dobbiamo considerare?
  2. Dopo il DWT rimane l'approssimazione finale lvl1. Ha senso non visualizzare la relazione dei coefficienti di dettaglio con il segnale originale, ma invece con il segnale originale meno l'approssimazione lvl1? (So ​​che molto probabilmente vedrei anche la relazione tra coefficienti e segnale senza farlo, vedere ad esempio i grafici di seguito. È solo per questo che ha senso o no. Dovrebbe avere senso per i coefficienti di dettaglio di livello 1, potrebbe anche avere senso per coefficienti di dettaglio lvl2 da confrontare con il segnale originale meno l'approssimazione lvl2, giusto?). Un esempio:

    # 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. La visualizzazione diretta della relazione tra i coefficienti di dettaglio e il segnale che uso traccia semplicemente sia il segnale che i coefficienti su un asse x di [0,1]. Ciò dovrebbe concettualmente essere valido, ma non sono sicuro che avrei effettivamente bisogno di un offset verso i margini (ad esempio, il primo e l'ultimo coefficiente del vettore non posizionato all'inizio o alla fine del segnale):

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

Relazione tra coefficienti di dettaglio lvl1 e segnale Relazione tra coefficienti di dettaglio lvl2 e segnale Relazione tra coefficienti di dettaglio lvl3 e segnale Relazione tra coefficienti di dettaglio lvl4 e segnale Relazione tra coefficienti di dettaglio lvl5 e segnale Relazione tra coefficienti di dettaglio lvl6 e segnale

Esiste una spiegazione intuitiva per i coefficienti forti che non sono direttamente nelle posizioni dei picchi nei dati originali (ad esempio al livello 1 il più basso (negativo più forte) a circa 0,25, nonché il più alto (positivo più forte) intorno a 0,75 )? Sebbene esista un modello chiaro (ritardo positivo + ampiezza negativa, ritardo negativo + ampiezza positiva), per me sembrano un po '"lontani". Ma c'è probabilmente una buona spiegazione per questo.

Grazie per aver risposto!


Non hai ottenuto una risposta, ma la tua stessa domanda è un buon tutorial per implementare l'analisi wavelet in Python. Grazie!
Farzad,

Risposte:


1

È necessario distinguere chiaramente tra i coefficienti di approssimazione e di dettaglio di ciascun livello di decomposizione e i livelli associati Dettagli e approssimazione che coinvolgono non solo i coefficienti ma anche i filtri inversi a quel livello rispettivamente


0

Sto solo ora iniziando a dilettarmi con le wavelet, e sto ancora lottando anche con domande molto basilari come "come si fa a scegliere dal gruppo di wavelet disponibili" (probabilmente ha a che fare con il numero di livelli necessari per raggiungere "abbastanza buono" rappresentazione) e "qual è tutto il problema del denoising con wavelet", perché mi sembra di essere in grado di ottenere risultati migliori per il mio tipo di dati con il denoising gaussiano o i filtri mediani. Ma sto divagando ....

Una cosa che ho notato in precedenza è che la tua numerazione dei livelli sembra incoerente con ciò che credo io le solite convenzioni wavelet. In particolare coeffs [0] è l'ampiezza di approssimazione all'ultimo livello, nel tuo caso 6 coeffs [1] è l'ampiezza del dettaglio al livello 6 coeffs [2] è l'ampiezza del dettaglio al livello 5 ... coeffs [6] è il ampiezza di dettaglio al livello 1

Quindi le tue ricostruzioni sono solo dai livelli 5 e 6, non dai livelli 1 e 2 come indicato nelle tue trame.

=========

Aggiornamento: ho incasinato di più il tuo codice e penso che la tua idea di illustrare la correlazione tra coefficienti e caratteristiche del segnale sia valida, ma non perfetta. Ho cercato un po 'il tuo codice per illustrarlo meglio, vedi sotto. Si noti che ad ogni passaggio ridimensiono i coefficienti in base all'entità del segnale. Ciò consente di parlare anche del concetto di soglia.

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)])
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.