Una ventana rectangular de longitud M tiene una respuesta de frecuencia de sin(ω*M/2)/sin(ω/2)
, que es cero cuando ω = 2*π*k/M
, para k ≠ 0. Para un DFT de longitud N, donde ω = 2*π*n/N
, hay nulos en n = k * N/M
. La relación N/M no es necesariamente un número entero. Por ejemplo, si N = 40 y M = 32, entonces hay nulos en múltiplos de 1.25, pero solo los múltiplos enteros aparecerán en el DFT, que son los contenedores 5, 10, 15 y 20 en este caso.
Así es un gráfico de la DFT 1024-punto de una ventana rectangular de 32 puntos:
M = 32
N = 1024
w = ones(M)
W = rfft(w, N)
K = N/M
nulls = abs(W[K::K])
plot(abs(W))
plot(r_[K:N/2+1:K], nulls, 'ro')
xticks(r_[:512:64])
grid(); axis('tight')
Nota los nulos en cada N/M = 32 bins. Si N = M (es decir, la longitud de la ventana es igual a la longitud DFT), entonces hay valores nulos en todas las ubicaciones excepto en n = 0.
Cuando multiplica una ventana por una señal, la operación correspondiente en el dominio de frecuencia es convolución circular del espectro de la ventana con el espectro de la señal. Por ejemplo, la DTFT de una sinusoide es una función delta ponderada (es decir, un impulso con altura infinita, extensión infinitesimal y área finita) ubicada en la frecuencia positiva y negativa de la sinusoide. La activación de un espectro con una función delta simplemente lo desplaza a la ubicación del delta y lo escala por el peso del delta. Por lo tanto, cuando se multiplica una ventana por una sinusoide en el dominio de muestra, la respuesta de frecuencia de la ventana se escala y se cambia a la frecuencia de la sinusoide.
Hay un par de escenarios para examinar con respecto a la longitud de una ventana rectangular. Primero veamos el caso donde la longitud de la ventana es un múltiplo entero del período de la sinusoide, p.una ventana rectangular 32-muestra de un coseno con un periodo de 32/8 = 4 muestras:
x1 = cos(2*pi*8*r_[:32]/32) # ω0 = 8π/16, bin 8/32 * 1024 = 256
X1 = rfft(x1 * w, 1024)
plot(abs(X1))
xticks(r_[:513:64])
grid(); axis('tight')
Como antes, hay valores nulos en múltiplos de N/M = 32. Sin embargo, la ventana de el espectro se ha desplazado al bin 256 de la sinusoide y se ha escalado por su magnitud, que está dividido en 0,5 entre la frecuencia positiva y la frecuencia negativa (solo estoy trazando frecuencias positivas). Si la longitud DFT hubiera sido 32, los nulos se alinearían en cada contenedor, lo que provocó la aparición de que no hay fugas. Pero esa apariencia engañosa es solo una función de la longitud DFT. Si rellena la señal de ventana con ceros (como se indicó anteriormente), verá la respuesta similar a sinc en las frecuencias entre los nulos.
Ahora veamos un caso en el que la longitud de la ventana no es un múltiplo entero del período de la sinusoide, p. un coseno con una frecuencia angular de 7.5π/16 (el período es de 64 muestras):
x2 = cos(2*pi*15*r_[:32]/64) # ω0 = 7.5π/16, bin 15/64 * 1024 = 240
X2 = rfft(x2 * w, 1024)
plot(abs(X2))
xticks(r_[-16:513:64])
grid(); axis('tight')
El centro de localización del compartimiento ya no está en un múltiplo entero de 32, pero desplazado en un medio hasta el contenedor 240. Veamos cuál sería el DFT de 32 puntos correspondiente (inferir una ventana rectangular de 32 puntos). Voy a calcular y representar gráficamente la DFT de 32 puntos de x2 [n] y también superponer una copia 32x diezmado del 1024 puntos DFT:
X2_32 = rfft(x2, 32)
X2_sample = X2[::32]
stem(r_[:17],abs(X2_32))
plot(abs(X2_sample), 'rs') # red squares
grid(); axis([0,16,0,11])
como se puede ver en el gráfico anterior , los nulos ya no están alineados en múltiplos de 32, por lo que la magnitud del DFT de 32 puntos no es cero en cada contenedor. En el DFT de 32 puntos, los nulos de la ventana todavía están espaciados cada N/M = 32/32 = 1 bin, pero desde ω0 = 7.5π/16, el centro está en 'bin' 7.5, lo que pone los nulos en 0.5, 1.5 , etc., por lo que no están presentes en el DFT de 32 puntos.
El mensaje general es que la fuga espectral de una señal de ventana es siempre presente pero puede ser enmascarado en la DFT si el specrtum señal, longitud de la ventana, y la longitud de DFT se unen en la forma correcta de alinear los nulos . Más allá de eso, simplemente debe ignorar estos artefactos DFT y concentrarse en la DTFT de su señal (es decir, rellenar con ceros para muestrear la DTFT a mayor resolución para que pueda examinar claramente la fuga).
La fuga espectral causada por la convolución del espectro de una ventana siempre estará allí, por lo que es tan importante el arte de crear ventanas con formas especiales. El espectro de cada tipo de ventana se ha diseñado para una tarea específica, como el rango dinámico o la sensibilidad.
He aquí un ejemplo que compara la salida de una ventana rectangular contra una ventana de Hamming:
from pylab import *
import wave
fs = 44100
M = 4096
N = 16384
# load a sample of guitar playing an open string 6
# with a fundamental frequency of 82.4 Hz
g = fromstring(wave.open('dist_gtr_6.wav').readframes(-1),
dtype='int16')
L = len(g)/4
g_t = g[L:L+M]
g_t = g_t/float64(max(abs(g_t)))
# compute the response with rectangular vs Hamming window
g_rect = rfft(g_t, N)
g_hamm = rfft(g_t * hamming(M), N)
def make_plot():
fmax = int(82.4 * 4.5/fs * N) # 4 harmonics
subplot(211); title('Rectangular Window')
plot(abs(g_rect[:fmax])); grid(); axis('tight')
subplot(212); title('Hamming Window')
plot(abs(g_hamm[:fmax])); grid(); axis('tight')
if __name__ == "__main__":
make_plot()
Ahh veo. Entonces, básicamente, las funciones de ventana son solo para 'modificar' o mejorar los datos de las muestras para mejorar los resultados del algoritmo de FFT. ¿Estoy en lo cierto? ¡Gracias! – user488792
@ user488792: sí, eso es más o menos: la función de ventana * suaviza * lo que de otro modo serían transitorios en los bordes de la ventana de muestreo. –
Sí, ya veo. Muchas gracias por la aclaración y por brindar una excelente respuesta. – user488792