Come rimuovere gli effetti di confine derivanti dall'assenza di padding in scipy / numpy fft?

6

Ho creato un codice Python per smussare un determinato segnale usando la trasformata di Weierstrass, che è fondamentalmente la convoluzione di un gaussiano normalizzato con un segnale.

Il codice è il seguente:

#Importing relevant libraries  
from __future__ import division  
from scipy.signal import fftconvolve   
import numpy as np 

def smooth_func(sig, x, t= 0.002):   
    N = len(x)   
    x1 = x[-1]   
    x0 = x[0]    


# defining a new array y which is symmetric around zero, to make the gaussian symmetric.  
    y = np.linspace(-(x1-x0)/2, (x1-x0)/2, N)   
    #gaussian centered around zero.  
    gaus = np.exp(-y**(2)/t)     

#using fftconvolve to speed up the convolution; gaus.sum() is the normalization constant.  
    return fftconvolve(sig, gaus/gaus.sum(), mode='same')

Se eseguo questo codice per dire una funzione di passaggio, smussa l'angolo, ma al confine interpreta un altro angolo e lo uniforma, dando come risultato un comportamento non necessario al confine. Spiego questo con una figura mostrata in questa immagine

Questo problema non si presenta se ci integriamo direttamente per trovare la convoluzione. Quindi il problema non è nella trasformata di Weierstrass, e quindi il problema è nella funzione fftconvolve di scipy.

Per capire perché questo problema si presenta, dobbiamo prima capire il funzionamento di fftconvolve in scipy.
La funzione fftconvolve utilizza fondamentalmente il teorema della convoluzione per accelerare il calcolo.

In breve dice:

convolution(int1,int2)=ifft(fft(int1)*fft(int2))  

Se applichiamo direttamente questo teorema non otteniamo il risultato desiderato. Per ottenere il risultato desiderato, dobbiamo prendere il fft su un array che raddoppia la dimensione di max (int1, int2). Ma questo porta agli effetti di confine indesiderati. Questo perché nel codice fft, se size (int) è maggiore della dimensione (oltre la quale prendere fft), esso azzera l'input e quindi prende il fft. Questo padding zero è esattamente ciò che è responsabile degli effetti di confine indesiderati.

Puoi suggerire un modo per rimuovere questi effetti di contorno?

Ho provato a rimuoverlo con un semplice trucco. Dopo aver levigato la funzione, ho confrontato il valore del segnale levigato con il segnale originale vicino ai limiti e se non corrispondono, sostituisco il valore della funzione levigata con il segnale di ingresso in quel punto.
È come segue:

i = 0 
eps=1e-3
while abs(smooth[i]-sig[i])> eps: #compairing the signals on the left boundary
    smooth[i] = sig[i]
    i = i + 1
j = -1

while abs(smooth[j]-sig[j])> eps: # compairing on the right boundary.
    smooth[j] = sig[j]
    j = j - 1

C'è un problema con questo metodo, a causa dell'uso di un epsilon ci sono piccoli salti in la funzione smussata .

Potrebbero esserci delle modifiche nel metodo sopra riportato per risolvere questo problema di limite?

    
posta Omkar 03.04.2012 - 18:28
fonte

2 risposte

1

Ci sono una varietà di modi per provare a risolvere le condizioni al contorno; è un problema che devi affrontare se stai conducendo una convoluzione diretta o una convoluzione basata su FFT. Sfortunatamente, non è chiaro esattamente quale sia la tua difficoltà (i tuoi grafici non hanno abbastanza contesto da permettermi di dire da dove vengono o cosa significano); nel seguito, dovrò indovinare.

La cosa di cui hai bisogno di ricordare sulla convoluzione basata su FFT è che tratta il suo input come un ciclo periodico. La tua domanda menziona un problema che "non sorge se ci integriamo direttamente per trovare la convoluzione"; questa differenza è probabilmente dovuta a questa proprietà.

Si sostiene che "il padding zero è responsabile degli effetti di confine indesiderati". Tuttavia, affinché la convoluzione FFT corrisponda ai risultati della convoluzione diretta, è necessario assicurarsi che sia sufficiente zero padding aggiunto ai dati originali per mantenere la natura periodica del FFT interferendo con la convoluzione. A tale scopo, ritengo che "sufficiente riempimento dello zero" debba essere la lunghezza del filtro con cui si sta convogliando. Prova a suddividere in modo uniforme lo zero padding per il tuo fftconvolve () tra l'inizio e la fine dell'esecuzione dei dati.

Se non sei soddisfatto degli effetti al contorno della tua convoluzione diretta, non sono sicuro di cosa dirti, dal momento che non so quale sia la tua domanda. Ti consiglierò che il risultato della tua convoluzione sarà lungo quanto i dati originali più la lunghezza del filtro, quindi dovrai provvedere a quello.

    
risposta data 04.04.2012 - 19:14
fonte
0

Utilizza gaussian_filter anziché fftconvolve .

Confronta il comportamento di fftconvolve (con mode='same' ) a gaussian_filter (con mode='constant' ) :

import numpy as np
from scipy.signal import fftconvolve
from scipy.ndimage import gaussian_filter

x = np.linspace(-3, 3, 51)
y = np.sin(x)

blurring_kernel = np.zeros_like(x)
blurring_kernel[25] = 1
blurring_kernel = gaussian_filter(blurring_kernel, sigma=3)

a = fftconvolve(y, blurring_kernel, mode='same')
b = gaussian_filter(y, sigma=3, mode='constant')
print max(abs((a - b))) # a and b are identical
"""
You have to assume *something* outside the boundary.
This is probably what you want:
"""
c = gaussian_filter(y, sigma=3, mode='reflect')

Devi assumere qualcosa al di fuori del confine del tuo segnale. fftconvolve assume zeri. gaussian_filter ti consente di scegliere tra diversi presupposti e trovo che uno di questi è in genere più vicino alle mie esigenze rispetto all'assunzione di zeri.

Per una soluzione rapida, puoi usare gaussian_filter , oppure tampona il tuo segnale con qualcosa di diverso da zero, per ottenere lo stesso effetto al confine, magari usando pad .

    
risposta data 03.01.2014 - 23:47
fonte

Leggi altre domande sui tag