Filtrado - multiplicación en dominio de frecuencia

7

Estoy tratando de crear un filtro de paso bajo simple, pero obtuve lo que considero un resultado sorprendente al observar la respuesta de frecuencia de un filtro Butterworth simple.

He copiado gran parte del ejemplo a continuación de esta otra publicación . He agregado un código en la parte inferior del script para comparar los espectros de entrada y salida con la respuesta de frecuencia del filtro. Esperaría que el espectro de salida sea ​​el producto del espectro de entrada y la respuesta de frecuencia : siUNAH

si=HUNA

Sin embargo, el gráfico a continuación muestra que el filtro en realidad aumenta algunos componentes de baja frecuencia; vea cómo la línea roja está por encima del verde debajo de .4 4 Hz

¿Alguien podría explicar por qué es esto?

import numpy as np
from scipy.signal import butter, lfilter, freqz
import matplotlib.pyplot as plt
from scipy.fftpack import fft as fft
def butter_lowpass(cutoff, fs, order=5):
    nyq = 0.5 * fs
    normal_cutoff = cutoff / nyq
    b, a = butter(order, normal_cutoff, btype='low', analog=False)
    return b, a

def butter_lowpass_filter(data, cutoff, fs, order=5):
    b, a = butter_lowpass(cutoff, fs, order=order)
    y = lfilter(b, a, data)
    return y


# Filter requirements.
order = 6
fs = 30.0       # sample rate, Hz
cutoff = 3.667  # desired cutoff frequency of the filter, Hz

# Get the filter coefficients so we can check its frequency response.
b, a = butter_lowpass(cutoff, fs, order)

# Plot the frequency response.
w, h = freqz(b, a, worN=8000)
plt.subplot(2, 1, 1)
plt.plot(0.5*fs*w/np.pi, np.abs(h), 'b')
plt.plot(cutoff, 0.5*np.sqrt(2), 'ko')
plt.axvline(cutoff, color='k')
plt.xlim(0, 0.5*fs)
plt.title("Lowpass Filter Frequency Response")
plt.xlabel('Frequency [Hz]')
plt.grid()


# Demonstrate the use of the filter.
# First make some data to be filtered.
T = 5.0         # seconds
n = int(T * fs) # total number of samples
t = np.linspace(0, T, n, endpoint=False)
# "Noisy" data.  We want to recover the 1.2 Hz signal from this.
data = np.sin(1.2*2*np.pi*t) + 1.5*np.cos(9*2*np.pi*t) + 0.5*np.sin(12.0*2*np.pi*t)

# Filter the data, and plot both the original and filtered signals.
y = butter_lowpass_filter(data, cutoff, fs, order)

plt.subplot(2, 1, 2)
plt.plot(t, data, 'b-', label='data')
plt.plot(t, y, 'g-', linewidth=2, label='filtered data')
plt.xlabel('Time [sec]')
plt.grid()
plt.legend()

plt.subplots_adjust(hspace=0.35)
plt.show()

def calculateFFT(time,signal):
    N=len(signal)      
    df=1/((time[-1]-time[0]))
    frequencies=[i*df for i in range(int(N/2.0))]
    fftValues = [2.0/N*abs(i) for i in fft(signal,N)[0:N/2.0] ]
    return frequencies,fftValues

plt.subplot(2, 1, 1)
originalfreqs,originalFFT=calculateFFT(t,data)
plt.plot(originalfreqs,originalFFT,"g",label="original")

filteredfreqs,filteredFFT=calculateFFT(t,y)
plt.plot(filteredfreqs,filteredFFT,"r",label="filtered")
plt.legend()

ingrese la descripción de la imagen aquí

James Dilworth
fuente

Respuestas:

4

Con mucho gusto voté por esta pregunta, porque así es como debería ser una buena pregunta, y también, cómo esperaría que los estudiantes verifiquen su comprensión de lo que aprenden. Siempre es bueno estar interesado en comprender el trasfondo de algo que desea usar más adelante.

El problema que experimenta es el siguiente: en principio tiene razón, que el teorema de convolución implica que la convolución en un dominio es multiplicación en el otro dominio. Por lo tanto tienes

F{X(t)h(t)}=X(F)H(F)
dónde F denota la Transformada de Fourier.

Entonces que es X(t) y h(t) en tu sistema? X(t)es su señal de entrada (en azul), que es la suma de tres senos, multiplicada por una ventana rectangular. Se multiplica implícitamente por un rectangular, porque su tiempo no (en simulación, no puede) llegar desde- a . Entonces, el espectro deX(F)es la convolución de una función sinc (desde la ventana rectangular) con tres Dirac (a la frecuencia de los senos). Claramente, este no es un espectro puramente discreto.

Que es h(t)? Es la respuesta al impulso del filtro de Butterworth. El filtro Butterworth tiene una respuesta de impulso infinitamente larga, de ahí su producto de convoluciónX(t)h(t)También es infinitamente ancho. Por lo tanto, en principio no puede aplicar una Transformada de Fourier finita (es decir, discreta) y esperar que sea similar al caso continuo.

Entonces, lo que ves es razonable. Puede intentar poner a cero la señal de entrada, de modo que obtenga (la parte principal de) la respuesta al impulso en su señal. Sin embargo, incluso entonces, verá las frecuencias, ya queX(F) No es discreto en realidad.

Maximilian Matthé
fuente
5

Para ampliar la respuesta de @ Maximilian Matthé , puede visualizar los efectos de fuga espectral (convolución de la función sinc en el dominio de la frecuencia) rellenando con cero las entradas utilizadas en . Por ejemplo, la siguiente función pone a cero las entradas a una longitudcalculateFFTk veces más largo que la entrada original (donde en este caso k=4 4):

def calculateFFT(time,signal):
    k=4
    N=k*len(signal)      
    df=1/(k*(time[-1]-time[0]))
    frequencies=[i*df for i in range(int(N/2.0))]
    fftValues = [k*2.0/N*abs(i) for i in fft(signal,N)[0:int(N/2.0)] ]
    return frequencies,fftValues

Al trazar el resultado, debería ver que los componentes de baja frecuencia realmente se superponen (lo que indica que el filtrado en realidad no aumenta la señal allí):

ingrese la descripción de la imagen aquí

Entonces, ¿de dónde provienen esas ondas alrededor de la espiga? Resulta que siempre estuvieron allí, pero cuando calculabas la FFT, obtenías el valor del espectro en un conjunto discreto de valores de frecuencia y esas ondas pasaban exactamente a cero en esas frecuencias. Si hubiera elegido una frecuencia de señal ligeramente diferente que no sea un múltiplo exacto de la resolución de frecuencia FFT (0.2Hz en su caso), por ejemplo 1.25Hz en lugar de 1.2Hz, el muestreo del espectro de frecuencia habría sido bastante diferente (debido a la frecuencia de muestreo en diferentes puntos en la oscilación de las ondas):

ingrese la descripción de la imagen aquí

DetectiveOjo
fuente