Algunas buenas respuestas aquí. Pensé que mostrar un ejemplo simple para usarlo en un contexto de procesamiento de señales sería más fácil de entender. He incluido el código y algunas parcelas, en caso de que quiera jugar con él.
No explicaré ninguna de las definiciones o detalles de convolución, ya que Sridhar dio una explicación realmente super intuitiva de eso, también lo hizo David. La respuesta de Mark ofrece algunas áreas de aplicación realmente interesantes que son mucho más interesantes que mi ejemplo, pero creo que comenzar con una señal simple es más fácil.
Primero, defina alguna función:
- Has viajado por el mundo durante un largo período de tiempo, ¿qué viene después cuando llegas a casa?
- ¿Es genial darse cuenta de la razón detrás de una teoría o resolver problemas en el contexto de las matemáticas?
- Cómo dividir 86 personas en grupos para que cada grupo tenga igual o más de 6
- ¿Cuántos números de 6 dígitos? se puede formar a partir de 1, 2, 3, 4, 5 y 6 sin repetición, de modo que el no. es divisible por el dígito en su lugar de la unidad?
- ¿Qué es una explicación intuitiva de una secuencia espectral?
[matemáticas] F (x) = \ sin (2 \ pi f_1 x) + \ sin (2 \ pi f_2 x) / 3 [/ matemáticas]
ff1 = 10 ff2 = 13 f = lambda f1, f2, x: np.sin (2 * np.pi * f1 * x) + np.sin (2 * np.pi * f2 * x) /3.0 x = np.arange (0,1,1. / 150) y = f (ff1, ff2, x)
Y luego agrega un poco de ruido gaussiano,
dy = 0.5 + 1.e-1 * np.random.random (forma y) ruido = np.random.normal (0, dy) ynoisy = y + ruido
Trace esos dos muy rápido:
Está bien. Ahora defina una función de suavizado que tome la convolución entre nuestra función ruidosa y alguna “ventana” (ver: Función de ventana):
def smooth (x, window_len = 11, window = 'hanning'): si x.size <window_len: raise ValueError, "El vector de entrada debe ser más grande que el tamaño de la ventana". si window_len <3: volver x s = np.r_ [x [window_len-1: 0: -1], x, x [-1: -window_len: -1]] if window == 'flat': # promedio móvil w = np.ones (window_len, 'd') más: w = eval ('np.' + ventana + '(window_len)') y = np.convolve (w / w.sum (), s, mode = 'valid') return y [(window_len / 2) :-( window_len / 2)]
Y luego pruebe un par de tipos de ventanas, como la ventana de Hamming
[matemáticas] W_ {hamming} (x) = 0.54 – 0.46 \ cos \ left (\ frac {2 \ pi x} {M – 1} \ right) [/ math]
donde [math] M [/ math] es el tamaño de la ventana en la dirección x (que es el segundo argumento para suavizar ()), que se ve así:
y la ventana plana
[matemática] W_ {plana} (x) = 1 [/ matemática]
y sabes cómo se ve eso (por cierto, los verdaderos geeks podrían notar que la ventana de Hamming no es exactamente apropiada para usar aquí, pero es solo un ejemplo aleatorio).
# Obtenga una función suavizada ys_ham = suave (y, window_len = 5, window = 'hamming') ys_flat = smooth (y, window_len = 5 window = 'flat')
Y ahora trama todo:
¡Frio! La ventana plana no funciona tan bien porque es solo una caja, pero la ventana de Hamming parece un poco gaussiana, por lo que esperamos que funcione decentemente bien y lo hace. Si observa la función ruidosa original por sí misma, es casi sorprendente que una herramienta matemática tan simple pueda extraer una representación casi perfecta de la función generadora subyacente.
Pero para el suavizado general de la señal, nos gusta usar una función gaussiana para nuestra ventana. Por supuesto, cuando uso una ventana gaussiana, el resultado se superpone exactamente con [math] F (x) [/ math]:
Para su información, no puede ingresar ‘gaussian’ como argumento para smooth (), tuve que agregar un elif para smooth (), aquí está la línea:
w = sp.signal.gaussian(window_len, 0.1)
y usted podría decir que estoy haciendo trampa aquí, y lo estoy, porque sé exactamente cuál era la variación del ruido y el hecho de que era gaussiano (para aclarar, el ruido está en la dirección y, así que estoy sin decir que está invirtiendo esto). Si hace que la varianza sea más grande, verá que comienza a desviarse (de hecho, si la hace lo suficientemente grande, verá que pierde uno de los términos en la función original).
Y finalmente, aquí hay un ejemplo con datos del mundo real (es la temperatura del agua durante una semana más o menos):
Aquí es más difícil decir qué funciona mejor porque no tenemos la verdad básica. Mirar el espectro de frecuencia de sus datos puede ayudar a decidir, pero, por supuesto, todo depende de lo que esté tratando de hacer.
De todos modos, aquí está el código en un solo lugar (nota: necesita numpy, scipy y matplotlib / pylab):
importar numpy como np importar scipy como sp importar pylab como plt de señal de importación scipy # Primero defina una función ff1 = 10 ff2 = 13 f = lambda f1, f2, x: np.sin (2 * np.pi * f1 * x) + np.sin (2 * np.pi * f2 * x) /3.0 x = np.arange (0,1,1. / 150) y = f (ff1, ff2, x) # Añadir algo de ruido dy = 0.5 + 1.e-1 * np.random.random (forma y) ruido = np.random.normal (0, dy) ynoisy = y + ruido # Definir la función de suavizado def smooth (x, window_len = 11, window = 'hanning', var = 0.1): "" " Tomado del libro de cocina scipy: http://wiki.scipy.org/Cookbook/SignalSmooth "" " si x.size <window_len: raise ValueError, "El vector de entrada debe ser más grande que el tamaño de la ventana". si window_len <3: volver x s = np.r_ [x [window_len-1: 0: -1], x, x [-1: -window_len: -1]] if window == 'flat': # promedio móvil w = np.ones (window_len, 'd') ventana elif == 'gaussiano': w = sp.signal.gaussian (window_len, var) más: w = eval ('np.' + ventana + '(window_len)') y = np.convolve (w / w.sum (), s, mode = 'valid') return y [(window_len / 2) :-( window_len / 2)] # Obtenga una función suavizada wlen = 5 ys_ham = suave (y, window_len = wlen, window = 'hamming') ys_flat = smooth (y, window_len = wlen, window = 'flat') ys_gauss = suave (y, window_len = wlen, ventana = 'gaussiano', var = 0.1) # Mostrar algunas parcelas plt.plot (x, y, 'k', ancho de línea = 3, etiqueta = "f (x)") plt.plot (x, ynoisy, 'g:', linewidth = 2, label = "Gaussian noise + f (x)") plt.plot (x, ys_ham, 'r', linewidth = 1, label = "Hamming window * f (x)") plt.plot (x, ys_flat, 'b', linewidth = 1, label = "Ventana plana * f (x)") plt.plot (x, ys_gauss, 'c--', linewidth = 3, label = "Ventana gaussiana * f (x)") plt.legend () plt.show ()
Por lo general, ver cómo implementar las matemáticas algorítmicamente me ayuda a comprenderlo mejor, así que si tiene curiosidad acerca de cómo se implementa la convolución, consulte el código fuente de Numpy en Github: https://github.com/numpy/numpy/ b …, aunque es cierto que este parece bastante críptico. Trataría de ayudar más con esto, pero dejaré que el detective trabaje contigo. Lo real para recordar es que está trabajando en un dominio discreto, así que simplemente extienda su dominio a la línea real (acotada) y reemplace la suma con una integral.